为什么实体框架的AsEnumerable()从服务器下载所有数据? [英] Why is Entity Framework's AsEnumerable() downloading all data from the server?

查看:54
本文介绍了为什么实体框架的AsEnumerable()从服务器下载所有数据?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

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

What is the explanation for EF downloading all result rows when AsEnumerable() is used?

我的意思是这段代码:

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

将从表中下载所有行,然后再将任何行传递给Where()方法,并且表中可能有数百万行.

will download all the rows from the table before passing any row to the Where() method and there could be millions of rows in the table.

我想做的是仅下载足以收集满足Id % 2 == 0条件的100行(很可能只有200行).

What I would like it to do, is to download only enough to gather 100 rows that would satisfy the Id % 2 == 0 condition (most likely just around 200 rows).

EF是否可以像使用普通ADO.NET使用SqlDataReaderRead()方法那样按需加载行并节省时间和带宽?

Couldn't EF do on demand loading of rows like you can with plain ADO.NET using Read() method of SqlDataReader and save time and bandwidth?

我认为它不能像这样工作是有原因的,我想听到一个很好的论据来支持该设计决策.

I suppose that it does not work like that for a reason and I'd like to hear a good argument supporting that design decision.

注意:这是一个完全人为的示例,我知道通常您不应该以这种方式使用EF,但是我在某些现有代码中发现了这一点,只是感到惊讶,因为我的假设被证明是错误的.

NOTE: This is a completely contrived example and I know normally you should not use EF this way, but I found this in some existing code and was just surprised my assumptions turned out to be incorrect.

推荐答案

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

The short answer: The reason for the different behaviors is that, when you use IQueryable directly, a single SQL query can be formed for your entire LINQ query; but when you use IEnumerable, the entire table of data must be loaded.

长答案:考虑以下代码.

context.Logs.Where(x => x.Id % 2 == 0)

context.Logs的类型为IQueryable<Log>. IQueryable<Log>.Where使用Expression<Func<Log, bool>>作为谓词. Expression代表抽象语法树;也就是说,它不仅仅是您可以运行的代码.可以认为它是在运行时在内存中表示的,就像这样:

context.Logs is of type IQueryable<Log>. IQueryable<Log>.Where is taking an Expression<Func<Log, bool>> as the predicate. The Expression represents an abstract syntax tree; that is, it's more than just code you can run. Think of it as being represented in memory, at runtime, like this:

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查询:

The LINQ-to-Entities engine can take context.Logs.Where(x => x.Id % 2 == 0) and mechanically convert it into a SQL query that looks something like this:

SELECT *
FROM "Logs"
WHERE "Logs"."Id" % 2 = 0;

如果将代码更改为context.Logs.Where(x => x.Id % 2 == 0).Take(100),则SQL查询将变为以下内容:

If you change your code to context.Logs.Where(x => x.Id % 2 == 0).Take(100), the SQL query becomes something like this:

SELECT *
FROM "Logs"
WHERE "Logs"."Id" % 2 = 0
LIMIT 100;

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

This is entirely because the LINQ extension methods on IQueryable use Expression instead of just Func.

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

Now consider context.Logs.AsEnumerable().Where(x => x.Id % 2 == 0). The IEnumerable<Log>.Where extension method is taking a Func<Log, bool> as a predicate. That is only runnable code. It cannot be analyzed to determine its structure; it cannot be used to form a SQL query.

这篇关于为什么实体框架的AsEnumerable()从服务器下载所有数据?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆