7

我有一个 LINQ to SQL 查询,如下所示:

var carIds = from car in _db.Cars
           where car.Color == 'Blue'
           select car.Id;

上面的最后会被翻译成下面的sql:

select Id from Cars 
where Color = 'Blue'

我读过这些阶段是:

  1. LINQ to Lambda 表达式
  2. Lambda 表达式到表达式树
  3. 表达式树到 SQL 语句
  4. SQL 语句被执行

所以,我的问题是何时以及如何翻译和执行?

我知道第 4 阶段发生在运行时,当我的“carIds”变量在 foreach 循环中被访问时。

foreach(var carId in carIds) // here?
{
  Console.Writeline(carId) // or here?
}

其他阶段呢?它们什么时候发生?在编译时还是运行时?在哪一行(在定义上或定义之后,访问时还是在访问之前)?

4

2 回答 2

3

您所说的是延迟执行-本质上,linq to SQL 查询将在您尝试枚举结果时执行(例如迭代它, .ToArray() 它等)。

在您的示例中,该语句在以下行执行:

foreach(var carId in carIds)

请参阅有关LINQ 和延迟执行的 MSDN 文章

于 2013-01-04T11:24:34.420 回答
2
  1. 由您、开发人员或 C# 编译器完成;您可以手动编写 lambda 表达式,或者使用 LINQ 语法,它们可以从 LINQ 中隐含(即被where x.Foo == 12视为好像是.Where(x => x.Foo == 12),然后编译器基于此处理步骤 2)
  2. 由 C# 编译器完成;它将“lambda 表达式”转换为构造(或在可能的情况下重用)表达式树的 IL。您也可以争辩说运行时是处理此步骤的内容
  3. 通常在枚举查询时完成,特别是在foreach调用时GetEnumerator()(甚至可能推迟到第一个.MoveNext

延迟执行允许组合查询;例如:

var query = ...something complex...
var items = query.Take(20).ToList();

这里Take(20)作为整体查询的一部分执行的,因此您不会从服务器带回所有内容,然后(在调用者处)将其过滤到前 20 个;从服务器只检索到 20 行。

您还可以使用编译查询将查询限制在第 4 步(或在某些情况下查询需要根据参数不同的 TSQL 的第 3 步和第 4 步)。或者,如果您只编写 TSQL,则可以跳过除 4 之外的所有内容。

您还应该添加一个步骤“5”:物化;这是一个相当复杂和重要的步骤。根据我的经验,物化步骤实际上可能是整体性能最重要的步骤(因此我们写了“dapper”)。

于 2013-01-04T11:24:42.133 回答