LINQ to Entities - OrderBy()。ToLisT()与ToList()。OrderBy()

时间:2012-12-11 19:22:33

标签: performance linq entity-framework linq-to-entities

我正在寻找这些LINQ表达式的确认/澄清:

var context = new SomeCustomDbContext()

// LINQ to Entities?
var items  = context.CustomItems.OrderBy(i => i.Property).ToList();

// LINQ to Objects?
var items2 = context.CustomItems.ToList().OrderBy(i => i.Property);

(Q1)我认为第一种方法是LINQ to Entities是正确的,其中EF构建了一个更具体的SQL语句来传递,将订购工作放在数据库上?

(Q2)第二种方法是LINQ to Objects,其中LINQ在订购之前将整个集合拖入内存(ToList()枚举?),从而在服务器端留下负担(在这种情况下是Web服务器)?

如果是这种情况,我可以很快看到L2E有利的情况(例如,在将它们拉入内存之前过滤/修剪集合)。

(Q3)但我是否应该注意任何其他细节/权衡,或“方法2”可能比第一种方法更有利的时候?

更新

假设我们没有使用EntityFramework,只要底层存储库/数据源实现IQueryable<T>,这仍然是正确的吗?如果不是这两个语句都导致内存中的LINQ to Objects操作?

3 个答案:

答案 0 :(得分:9)

  1. 你是正确的,调用ToList()强制linq-to-entities评估并将结果作为列表返回。正如您所怀疑的那样,这可能会产生巨大的性能影响。

    有些情况下linq-to-entities无法弄清楚如何解析看起来像一个非常简单的查询(如Where(x => SomeFunction(x)))。在这些情况下,您通常别无选择,只能致电ToList()并对内存中的集合进行操作。


    响应您的更新:

    ToList()总是迫使所有事情立即进行评估,而不是延迟执行。举个例子:

    someEnumerable.Take(10).ToList();
    

    VS

    someEnumerable.ToList().Take(10);
    

    在第二个示例中,必须在获取前10个元素之前执行someEnumerable上的任何延迟工作。如果someEnumerable正在做一些劳动密集型工作(比如使用Directory.EnumerateFiles()从磁盘读取文件),这可能会产生非常实际的性能影响。

答案 1 :(得分:3)

  

我是否认为第一种方法是LINQ to Entities,其中EF构建了一个更具体的SQL语句来传递,将订购工作放在数据库上?

  

第二种方法LINQ to Objects LINQ将整个集合拖入内存......在订购之前将负担留在服务器端......?

  

但我是否应该注意任何其他细节/权衡,或者“方法2”可能比第一种方法更有利的时候?

很多时候方法1都不可能 - 通常当你有一个复杂的过滤器或排序顺序无法直接转换为SQL时(或者更适当的地方,EF不支持直接的SQL转换)。此外,由于您无法通过线路传输延迟加载的IQueryable,因此无论何时必须序列化结果,您都必须首先使用ToList()或类似的东西来实现它。

答案 2 :(得分:0)

要注意的另一件事是IQueryable不能保证(a)底层提供者的语义推理,或者(b)提供者实现了多少IQueryable方法。

例如: -

  1. EF不支持Last()。
  2. 它也不支持将DateTimes时间部分比较为有效的T-SQL。
  3. 它不支持子查询中的FirstOrDefault()。
  4. 在这种情况下,您需要将数据带回客户端,然后在客户端执行进一步的评估。

    您还需要了解它如何解析LINQ管道以生成(在EF的情况下)T-SQL。因此,有时您必须仔细考虑如何构建LINQ查询以生成有效的T-SQL。

    说了这么多,IQueryable&lt;&gt;是.NET框架中非常强大的工具,非常值得熟悉。