4

所以,这是我的代码:

注意 ToList() 这里方法的位置,它是 IEnumerable,逐行比较。

Customers.ToList().Where(m=>m.ID > 3).OrderByDescending(m=>m.Name).FirstOrDefault();

Customers.Where(m=>m.ID > 3).ToList().OrderByDescending(m=>m.Name).FirstOrDefault();

Customers.Where(m=>m.ID > 3).OrderByDescending(m=>m.Name).ToList().FirstOrDefault();

让我们逐行浏览它:

Customers.ToList().Where(m=>m.ID > 3) .OrderByDescending(m=>m.Name).FirstOrDefault()

  • .ToList() - 可枚举
  • .Where() - 可枚举
  • .OrderByDescending() - 可枚举
  • .FirstOrDefault - 可枚举

Customers.Where(m=>m.ID > 3).ToList() .OrderByDescending(m=>m.Name).FirstOrDefault()

  • .Where() -可查询
  • .ToList() - 可枚举
  • .OrderByDescending() - 可枚举
  • .FirstOrDefault() - 可枚举

Customers.Where(m=>m.ID > 3).OrderByDescending(m=>m.Name) .ToList().FirstOrDefault()

  • .Where() -可查询
  • .OrderByDescending() - 可查询
  • .ToList() - 可枚举
  • .FirstOrDefault() - 可枚举

现在,这是他们的 SQL,按顺序排列:

选择 [t0].[ID], [t0].[Name] 从 [Customer] AS [t0] GO

SELECT [t0].[ID], [t0].[Name] FROM [Customer] AS [t0] WHERE [t0].[ID]

SELECT TOP (1) [t0].[ID], [t0].[Name] FROM [Customer] AS [t0] WHERE [t0].[ID] > @p0 ORDER BY [t0].[Name] DESC

似乎 line1 获得了整个集合并将其通过线路传递,而 line3 仅获得一个实体。

根据 SQL 输出,我可以推断:

    line1: 内存密集型代码;需要更多带宽,因为更多数据在线路中传递;
    line3: 数据库密集型代码;需要更少的带宽,因为在线路中传递的数据更少

我很好奇每行代码之间的内部情况。它们相对相似,我得到了相同的确切结果

这里到底发生了什么(在 C# 及其特性的内部?)?

4

2 回答 2

4

.ToList()方法使其可枚举并在那时生成 SQL。之后,您将使用 LINQ to Objects。

因此,例如,在第一行,您将获得整张桌子,因为您正在调用 .ToList().Customers

这不是一个好的解决方案,因为您将整个记录都放入您的内存中,因此.ToList()如果之前没有理由调用它,请始终在查询结束时调用它。

于 2012-04-13T07:15:41.970 回答
4

类似.Where().OrderBy()使用延迟执行的方法,这意味着它们在调用时所做的只是修改查询的表达式树——它们不会导致查询被执行。底层查询只有在被某些东西枚举时才会执行(例如,通过对其进行 foreach)。

.ToList()另一方面,它旨在返回查询结果的内存列表,也就是说,它实际上导致查询被执行。它在概念上类似于执行以下伪代码

foreach (item in query)
   list.add(item) 

在您的示例中,查询由 执行,.ToList()并且从那时起您正在执行新查询,这次是针对内存中的集合。

因此,在第一个示例中,客户查询由 ToList() 立即执行,.Where()并且.OrderBy()仅使用 Linq to objects 查询提供程序修改新的表达式树,并且此 Linq to objects 查询由FirstOrDefault().

于 2012-04-13T07:29:22.663 回答