C# IQueryable LINQ Group By with null values.

问题描述 投票:0回答:1

我想根据一个属性从数据库中选择不同的值,当该属性是 null. IDs 在我的数据库里有 Strings

我的数据库是这样的。

Id1   Id2    Value
____________________
1     null   Value1
2     1      Value2
3     1      Value3
4     null   Value4
5     null   Value5
6     2      Value6
7     2      Value7
8     2      Value8

我想从我的查询中得到这样的输出。

Id1   Id2    Value
____________________
1     null   Value1
2     1      Value2  // i dont care which one from Id2 = 1 i get
4     null   Value4
5     null   Value5
6     2      Value6  // i dont care which one from Id2 - 2 i get

如你所见,我想得到一个 List 的所有元素,其中 Id2 为空,只返回一个元素,其中 Id2 是一样的(我不在乎哪个元素查询会返回)。

我试着编写一些代码。

query
   .Where(x => !string.IsNullOrEmpty(x.Id2))
   .GroupBy(z => z.Id2)
   .Select(grp => grp.FirstOrDefault())
   .ToListAsync();

但我没有得到我想要的东西,只有一个项目的表示方式。Id2 而只有一个 null 值,类似这样。

Id1   Id2    Value
____________________
1     null   Value1
2     1      Value2  // I want to get all elements where Id2 = null
6     2      Value6  // and distinct elements based on Id2

我的问题是,如何写查询EF 得到所有的空项目和所有基于属性的不同项目?

c# linq entity-framework-core
1个回答
1
投票

未测试。

var result = query.Where(x => x.Id2 == null || !query.Any(y => y.Id2 == x.Id2 && string.Compare(y.Id1, x.Id1) < 0))

这应该可以得到所有的行 Id2 is null 而只有最小的那一行 Id1 对于每一组 Id2


1
投票

在你的GroupBy之后,你有一个Group的序列。组的Key是Id2的值。

如果Key(Id2)不是空的,你只想要组中的一个元素,你不关心是哪一个。

如果Key等于空,则需要该组的所有元素。

有两种方法可以做到这一点。

  • 对所有非空元素进行GroupBy处理
  • 将其与null元素并列

或者。

  • 使用GroupBy的ResultSelector参数来检查Key是否为空,然后只选择一个元素,或者选择该组的所有元素。

连接法

IQueryable<MyClass> source = dbContext....

// the elements with non-null Id2, keep only one element:
IQueryable<MyClass> filledId2 = source
    .Where(item => item.Id2 != null)
    .GroupBy(item => item.Id2,

        // Parameter ResultSelector, take Id2 (key) and all items with this Id2
        // to make one new:
        (key, itemsWithThisKey) => itemsWithThisKey.FirstOrDefault());

注意:不会有任何空组,所以结果中没有 "默认 "项。

Id2为空的元素。

IQueryable<MyClass> emptyId2 = source.Where(item => item.Id2 == null);

连接。

var result = filledId2.Concat(emptyId2);

注意:还没有执行查询。如果需要,你可以创建一个大的LINQ语句。这不会提高效率。但是会降低可读性。

ResultParameter方法

   IQueryable<MyClass> filledId2 = source.GroupBy(item => item.Id2,

       // resultSelector: if the key is null, select all elements of the group
       // otherwise select a sequence of one element of the group
       (key, itemsWithThisKey) => (key == null) ? 
             itemsWithThisKey : itemsWithThisKey.Take(1))

       // result: a sequence of sequences of MyClass objects
       // use SelectMany to make it one sequence of MyClass objects:
       .SelectMany(group => group);
© www.soinside.com 2019 - 2024. All rights reserved.