c# 了解 LINQ 查询中的 AsEnumerable
c# Understanding AsEnumerable in LINQ query
下面的代码:
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);
我收到 运行 时间错误:指定的类型成员 'Date' 在 LINQ to Entities 中不受支持。仅支持初始化器、实体成员和实体导航属性
当我将 _db.Members.AsEnumerable() 添加到第一行时,它起作用了。
我的理解是 .AsEnumerable() 强制查询在客户端执行。所以在上面的代码中,AsEnumerable 运算符在服务器端将查询分成两部分 select 并在客户端休息(分组依据,位置)。
有人可以验证我的理解是否正确吗?以及为什么代码在没有 .AsEnumerable() 的情况下失败?
您的理解是正确的。调用AsEnumerable
后无法再查询数据源,退回到简单的"give me everything"模式,即所有数据传输到客户端,任何进一步的操作都在本地完成。
这也是查询无法按书面方式工作的原因:为了使其工作,您在 LINQ 方法中使用的所有表达式都必须可翻译为您的数据源可以理解的任何语言——并且自从进行翻译是 query provider 的责任,您也将受到编程支持的限制。
在这种特定情况下(假设为 EF),可以通过手动将 属性 访问替换为规范函数 TruncateTime
:
来修复查询以在可查询模式下工作
.Where(m => m.All(s => s.Status == 1)
&& EntityFunctions.TruncateTime(m.Key.CreatedDate) ==
EntityFunctions.TruncateTime(CurrentDateTime()))
AsEnumerable 在您想切换到 LINQ to Objects 时经常使用,主要是因为您想使用一些 Linq to Entities 不支持。当您使用 AsEnumerable()
时,您正在转换为 IEnumerable<T>
并且它基本上将处理从数据源(具有所有数据和索引等)移动到您的应用程序。换句话说,如果您不使用 AsEnumerable(),LINQ to Entities 会将您的查询转换为 SQL 并且它将在您的数据源中远程执行。如果您想查看有关此主题的更多信息,我建议您阅读这篇文章 post。
正如 Jon 所说,Entity Framework 提供了一组用于处理日期的函数,这些函数可以直接转换为 SQL,这些在EntityFunctions
命名空间。这些映射到所谓的 "canonical functions" 这只是意味着有 1:1 翻译成 SQL
下面的代码:
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);
我收到 运行 时间错误:指定的类型成员 'Date' 在 LINQ to Entities 中不受支持。仅支持初始化器、实体成员和实体导航属性
当我将 _db.Members.AsEnumerable() 添加到第一行时,它起作用了。
我的理解是 .AsEnumerable() 强制查询在客户端执行。所以在上面的代码中,AsEnumerable 运算符在服务器端将查询分成两部分 select 并在客户端休息(分组依据,位置)。
有人可以验证我的理解是否正确吗?以及为什么代码在没有 .AsEnumerable() 的情况下失败?
您的理解是正确的。调用AsEnumerable
后无法再查询数据源,退回到简单的"give me everything"模式,即所有数据传输到客户端,任何进一步的操作都在本地完成。
这也是查询无法按书面方式工作的原因:为了使其工作,您在 LINQ 方法中使用的所有表达式都必须可翻译为您的数据源可以理解的任何语言——并且自从进行翻译是 query provider 的责任,您也将受到编程支持的限制。
在这种特定情况下(假设为 EF),可以通过手动将 属性 访问替换为规范函数 TruncateTime
:
.Where(m => m.All(s => s.Status == 1)
&& EntityFunctions.TruncateTime(m.Key.CreatedDate) ==
EntityFunctions.TruncateTime(CurrentDateTime()))
AsEnumerable 在您想切换到 LINQ to Objects 时经常使用,主要是因为您想使用一些 Linq to Entities 不支持。当您使用 AsEnumerable()
时,您正在转换为 IEnumerable<T>
并且它基本上将处理从数据源(具有所有数据和索引等)移动到您的应用程序。换句话说,如果您不使用 AsEnumerable(),LINQ to Entities 会将您的查询转换为 SQL 并且它将在您的数据源中远程执行。如果您想查看有关此主题的更多信息,我建议您阅读这篇文章 post。
正如 Jon 所说,Entity Framework 提供了一组用于处理日期的函数,这些函数可以直接转换为 SQL,这些在EntityFunctions
命名空间。这些映射到所谓的 "canonical functions" 这只是意味着有 1:1 翻译成 SQL