9

我正在寻找这些 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 EntitiesEF 构建更具体的 SQL 语句以传递,将排序工作放在数据库上?

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

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

  3. 但是是否还有其他我应该注意的细节/权衡,或者“方法 2”可能优于第一种方法的时间?

更新:

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

4

3 回答 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);

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

于 2012-12-11T19:27:23.793 回答
3

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

是的

第二种方法是 LINQ to Objects,其中 LINQ 将整个集合拖到内存中……在订购之前,从而给服务器端留下负担……?

是的

但是是否还有其他我应该注意的细节/权衡,或者“方法 2”可能优于第一种方法的时间?

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

于 2012-12-11T19:28:17.677 回答
0

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

例如: -

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

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

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

说了这么多,IQueryable<> 是 .NET 框架中一个非常强大的工具,非常值得更加熟悉。

于 2012-12-11T20:02:04.860 回答