【问题标题】:EF - DistinctBy on an IQueryable?EF - IQueryable 上的 DistinctBy?
【发布时间】:2015-09-16 21:48:10
【问题描述】:

假设我有这个,我想获取第 42 组中的每个人,但我想获取数据库中每个唯一名字的 IQueryable(PS - 我知道我可以在 Select 之后调用 AsQueryable() 但这不是我有兴趣做什么 - 我希望数据库执行不同的操作,而不是程序):

MyEfContextContainer db = new MyEfContextContainer();
IQueryable<string> uniqueFirstNames = 
    db.People
    .Where(x=> x.GroupId == 42)
    .DistinctBy(c=> c.FirstName)
    .Select(c=> c.FirstName);

据我所知,EF/LINQ to Entities 如何处理 DistinctBy 扩展方法,在调用 DistinctBy 时执行存储查询,并检索数据库中与 Where 匹配的所有项目的列表,然后 C# 返回一个IEnumberable 从 DistinctBy 方法匹配发送到 DistinctBy 的表达式。

如果列表中有数百万个名字,这是非常低效的。

我对能够有效地做到这一点很感兴趣,希望通过让商店查询只返回表中所有唯一名字的结果集。例如,我可能希望将该 IQueryable 作为存储库的一部分返回,由于性能原因,让 DistinctBy 抓取和处理数百万个项目以仅返回唯一值是不合适的。这会将请求处理时间增加到不可接受的程度。

有没有办法做到这一点?我错过了什么吗?这只是一个简单的示例,显然在实际应用程序中,比字符串更复杂的对象将成为存储库查询的主题。

【问题讨论】:

    标签: entity-framework linq-to-entities


    【解决方案1】:

    我写了这个扩展:

    public static IQueryable<TSource> DistinctBy<TSource, TKey>  (this IQueryable<TSource> source, Expression<Func<TSource, TKey>> keySelector)
    {
        return source.GroupBy(keySelector).Select(x => x.FirstOrDefault());
    }
    

    根据属性做出不同的选择,例如身份证,我只是打电话:

    res = res.DistinctBy(x => x.Id);
    

    【讨论】:

      【解决方案2】:

      IQueryable 你必须自己做:

      db.People
        .Where(x => x.GroupId == 42)
        .GroupBy(c => c.FirstName)
        .Select(g => g.FirstOrDefault());
      

      MoreLinq 的DistinctBy 方法是IEnumerable&lt;T&gt; 的扩展方法,因此它接受IQueryable&lt;T&gt;,但在方法内部它充当IEnumerable&lt;T&gt;。和db.People.AsEnumerable().DistinctBy()效果一样

      【讨论】:

      • 知道了,我知道我可以做到,但我不确定这是否适合我的用例......让我看看。
      【解决方案3】:

      从你的 NuGet 包管理器安装 morelinq,你将能够使用 DistinctBy 和 IQueryable

      【讨论】:

      • 不,请仔细阅读问题:我希望数据库执行 distinct,而不是程序。 MoreLinq 不这样做。
      猜你喜欢
      • 2015-03-29
      • 2015-01-18
      • 1970-01-01
      • 2020-05-12
      • 2018-10-27
      • 1970-01-01
      • 1970-01-01
      • 2018-10-17
      • 1970-01-01
      相关资源
      最近更新 更多