EF - 区别于IQueryable?

Pug*_*ugz 10 linq-to-entities entity-framework

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

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

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

如果列表中有数百万个名称,则效率非常低.

我有兴趣能够有效地执行此操作,希望通过使商店查询仅返回表中所有唯一FirstNames的结果集.例如,我可能希望将IQueryable作为存储库的一部分返回,因为性能原因不能通过DistinctBy抓取和处理数百万个项目来返回唯一值.这会将请求处理时间增加到不可接受的水平.

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

小智 11

我写了这个扩展名:

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

要基于属性进行不同的选择,例如Id,我只需要调用:

res = res.DistinctBy(x => x.Id);
Run Code Online (Sandbox Code Playgroud)


Ger*_*old 9

随着IQueryable你必须自己做:

db.People
  .Where(x => x.GroupId == 42)
  .GroupBy(c => c.FirstName)
  .Select(g => g.FirstOrDefault());
Run Code Online (Sandbox Code Playgroud)

MoreLinq的DistinctBy方法是一个扩展方法IEnumerable<T>,所以它接受一个IQueryable<T>,但在方法内部它充当一个IEnumerable<T>.它与做同样的效果db.People.AsEnumerable().DistinctBy()