linq - 为什么 Entity Framework 的 AsEnumerable() 从服务器下载所有数据?

标签 linq entity-framework

AsEnumerable()时EF下载所有结果行的解释是什么用来?

我的意思是这段代码:

context.Logs.AsEnumerable().Where(x => x.Id % 2 == 0).Take(100).ToList();

将在将任何行传递给 Where() 之前从表中下载所有行方法,表中可能有数百万行。

我希望它做的是下载仅足以收集满足 Id % 2 == 0 的 100 行。条件(很可能只有大约 200 行)。

EF 不能像使用 Read() 的普通 ADO.NET 那样按需加载行SqlDataReader的方法并节省时间和带宽?

我想它不会那样工作是有原因的,我想听到一个支持该设计决定的好论据。

注意 :这是一个完全人为设计的示例,我知道通常您不应该以这种方式使用 EF,但是我在一些现有代码中发现了这一点,并且很惊讶我的假设结果是不正确的。

最佳答案

简答:不同行为的原因是,当您使用 IQueryable 时直接,可以为整个 LINQ 查询形成单个 SQL 查询;但是当你使用 IEnumerable ,必须加载整个数据表。

长答案:考虑以下代码。

context.Logs.Where(x => x.Id % 2 == 0)
context.Logs类型为 IQueryable<Log> . IQueryable<Log>.Where正在服用 Expression<Func<Log, bool>>作为谓词。 Expression表示抽象语法树;也就是说,它不仅仅是您可以运行的代码。可以将其视为在内存中在运行时表示,如下所示:
Lambda (=>)
  Parameters
    Variable: x
  Body
    Equals (==)
      Modulo (%)
        PropertyAccess (.)
          Variable: x
          Property: Id
        Constant: 2
      Constant: 0

LINQ-to-Entities 引擎可以采用 context.Logs.Where(x => x.Id % 2 == 0)并机械地将其转换为如下所示的 SQL 查询:
SELECT *
FROM "Logs"
WHERE "Logs"."Id" % 2 = 0;

如果您将代码更改为 context.Logs.Where(x => x.Id % 2 == 0).Take(100) ,SQL 查询变成这样:
SELECT *
FROM "Logs"
WHERE "Logs"."Id" % 2 = 0
LIMIT 100;

这完全是因为 IQueryable 上的 LINQ 扩展方法使用 Expression而不仅仅是 Func .

现在考虑 context.Logs.AsEnumerable().Where(x => x.Id % 2 == 0) . IEnumerable<Log>.Where扩展方法是 Func<Log, bool>作为谓词。那只是可运行的代码。无法对其进行分析以确定其结构;它不能用于形成 SQL 查询。

关于linq - 为什么 Entity Framework 的 AsEnumerable() 从服务器下载所有数据?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/31837028/

相关文章:

c# - 将 if-chain 转换为基于规则的字典

c# - Entity Framework 中的 ApplicationUserContext 为 null

asp.net-mvc - 使用 Entity Framework 连接到在Docker容器中运行的MySQL数据库

c# - 如何在模型类上添加与数据库无关的属性?

c# - I可查询。比较运算符(== 和 >=)的细节

c# - 合并列表中的重复字符串并求和

entity-framework - 反射(reflect)对 Entity Framework 生成的复杂类型中的存储过程所做的更改

c# - 获取导致异常的查询

vb.net - 在 VB.NET 中通过 LINQ 对通用列表进行分组

asp.net - 如何通过 LINQ 获得一级子级