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/