C#:理解LINQ查询中的AsEnumerable (注意:这是一个提问标题,无需回答)

4
以下代码:

code

var mids = _db.Members
     .GroupBy(m => new { m.MemberID, m.CreatedDate })
     .Where(m => m.All(s => s.Status == 1) && m.Key.CreatedDate.Date == DateTime.Today)
     .Select(m=>m);

我收到一个运行时错误:在LINQ to Entities中不支持指定的类型成员'Date'。只支持初始化程序、实体成员和实体导航属性。
当我在第一行添加'_db.Members.AsEnumerable()'时,它可以工作。
我的理解是,.AsEnumerable()强制查询在客户端上执行。因此,在上面的代码中,AsEnumerable运算符将查询分为两个部分:在服务器端选择和在客户端上进行其余操作(分组、筛选等)。
有人能验证我的理解是否正确吗?为什么没有.AsEnumerable()代码会失败?

是的,你说得对。顺便提一下,你不能使用linq to sql语法这样比较日期。 - Vsevolod Goloviznin
2个回答

4
您的理解是正确的。调用AsEnumerable后,数据源无法再被查询,而会退回到一个简单的“给我所有数据”的模式,这意味着所有数据都会传输到客户端,并且任何进一步的操作都是在本地完成。
这也是查询不能按原样工作的原因:为了使其正常工作,LINQ方法中使用的所有表达式都必须可翻译成数据源所理解的语言 - 并且由于翻译是由查询提供程序负责执行的,因此您也将受制于其支持的内容。
在这种特定情况下(假设是EF),可以通过手动替换属性访问为规范函数TruncateTime来修复查询,以在可查询模式下工作。
.Where(m => m.All(s => s.Status == 1) 
    && EntityFunctions.TruncateTime(m.Key.CreatedDate) ==
       EntityFunctions.TruncateTime(CurrentDateTime()))

这不是LINQ2Entities吗?Ben的帖子中提到了它。 - Arkadiusz Kałkus
谢谢Jon的解释。因此,如果使用EF,您建议使用您的方法,因为条件将在数据源上执行,它将在服务器端执行?如果使用AsEnumerable,则会返回所有信息并返回其他信息。更多可能没有用处的数据。 - Benk
@Landeeyo EntityFunctions 是为任何“实体”系统设计的,包括 Linq2Entitys 和 EF。重要的是您的提供程序知道如何理解函数调用(默认提供程序可以) 。 - Scott Chamberlain
@Ben 是的,如果可以实现的话,服务器端执行总是您想要的。 - Jon
你能分享一下使用.AsEnumerable的场景吗?如果你知道一篇好文章,请分享。感谢你的帮助。 - Benk
@Ben:如果你想在某个时刻运行自己的任意代码,那么你可以使用 AsEnumerable。例如,db.Members.Select(m => MyOwnCode(m)) 显然永远无法转换为存储表达式——MyOwnCode 可以做任何事情,这显然无法转换为 SQL。在这种情况下,你必须使用 AsEnumerable 来告诉 LINQ:“我知道你不能做到这一点,所以别试了”。 - Jon

2
AsEnumerable 经常用于切换到LINQ to Objects,主要是因为您想使用一些Linq to Entities不支持的功能。当您使用 AsEnumerable() 时,您正在转换为 IEnumerable<T>,它基本上将处理从数据源(具有所有数据和索引等)移动到您的应用程序。换句话说,如果您不使用 AsEnumerable()LINQ to Entities 将会将您的查询翻译成 SQL,并在您的数据源中远程执行。如果您想了解更多关于此主题的信息,我建议您阅读这篇文章
正如 Jon 所说,Entity Framework 提供了一组可直接转换为 SQL 的日期处理函数,这些函数位于 EntityFunctions 命名空间中。这些映射到所谓的“规范函数”,这只是意味着存在 1:1 的 SQL 翻译。

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接