LINQ to Entities -- OrderBy().ToList() vs. ToList().OrderBy() LINQ to Entities--OrderBy().ToList()与ToList().OrderBy()的区别

10

我希望确认/澄清以下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);
  1. 我想问的第一种方法是LINQ to Entities,即EF生成更具体的SQL语句进行传递,将排序工作放在数据库上,我的理解是否正确?

  2. 第二种方法是LINQ to Objects,LINQ将整个集合拖入内存(使用ToList()枚举?)然后排序,从而将负担留给服务器端(在这种情况下是Web服务器)吗?

    如果是这样,我可以很快看到L2E会有优势的情况(例如,在将集合拉入内存之前对其进行过滤/修剪)。

  3. 但是,我还应该了解其他详细信息/权衡,或者什么时候“方法2”可能比第一种方法更有优势吗?

更新:

假设我们不使用EntityFramework,只要底层存储库/数据源实现了IQueryable<T>,这仍然是真的,对吧?如果没有,这两个语句都会在内存中执行LINQ to Objects操作?

3个回答

11
  1. 是的。
  2. 是的。
  3. 是的。

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

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


针对您的更新:

ToList() 总是强制立即评估它之前的所有内容,而不是延迟执行。以这个例子为例:

someEnumerable.Take(10).ToList();

对手

someEnumerable.ToList().Take(10);
在第二个示例中,在获取前10个元素之前必须执行someEnumerable上的任何延迟工作。如果someEnumerable正在执行一些费力的操作(例如使用Directory.EnumerateFiles()从磁盘读取文件),则可能会对性能产生非常实际的影响。

1
@JonB:你能否详细解释一下这个问题:“有些情况下,linq-to-entities无法理解看起来非常简单的查询(比如Where(x => SomeFunction(x)))的解析方式?” - Pawel
1
@Pawel Equals() 是一个方法,它会被 LINQ to ENTITIES 转换成一个 LINQ to SQL 语句。 - Bob.
@Pawel,JonB。谢谢。正是所需的。虽然我也想要一个Equals()或类似翻译问题的例子。 - one.beat.consumer
@Pawel 当使用LINQ-to-entities时,EF必须将您的LINQ解析为其他形式(如SQL)。如果查询中有某些内容没有相应的等效项(如函数调用),则不能执行该操作。在使用EF和SQL时,执行myTable.Where(x => x.Equals(...))将导致运行时错误。我不是EF大师,所以可能无法解释更多。关键在于调用ToList()将把所有内容带回到LINQ-to-objects域,这简单且功能更强大,但潜在地要慢得多。 - Jon B
是的。Linq to Entity查询被翻译成特定于数据库的SQL。是的 - 如果没有SQL翻译,EF会抛出异常。Equals(如上所示)应该有效,除非您正在与EF不理解的对象进行比较,因此无法将其翻译为SQL。但是,如果您使用这样的对象,则可能意味着您的业务逻辑泄漏到数据库中,数据库将永远无法将列值与随机数据进行比较,因此您需要将它们分开。是的 - .ToList()强制查询评估并可以将整个数据库带到客户端,因此您需要编写... - Pawel
显示剩余3条评论

3
我正确地认为第一种方法是LINQ to Entities,其中EF构建了一个更具体的SQL语句来传递,将排序工作放在数据库上吗?
是的
第二种方法是LINQ to Objects,LINQ将整个集合拖入内存中进行排序,因此将负担留给服务器端吗?
是的
但是我应该注意到任何其他细节/权衡,或者什么时候“方法2”可能比第一种方法更有优势吗?
通常情况下,当您有复杂的筛选或排序顺序无法直接转换为SQL(或更恰当的情况是EF不支持直接的SQL转换)时,Method 1无法实现。此外,由于无法通过网络传输延迟加载的IQueryable,因此每当您必须序列化结果时,都需要首先使用ToList()或类似的内容将其具体化。

我认为你刚刚也回答了我的更新——如果源代码只实现了IEnumerable<T>,那么这些语句本质上并没有什么不同? - one.beat.consumer
2
不一定;IEnumerable<T> 也可以以惰性方式实现。 - D Stanley

0

需要注意的另一件事是,IQueryable 不保证底层提供程序的语义推理或 IQueryable 方法集的实现程度。

例如:

  1. EF 不支持 Last()。
  2. 它也不支持将 DateTime 的时间部分比较为有效的 T-SQL。
  3. 它不支持子查询中的 FirstOrDefault()。

在这种情况下,您需要将数据带回客户端,然后在客户端执行进一步的评估。

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

尽管如此,IQueryable<> 是 .NET 框架中非常强大的工具,值得更加熟悉。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接