作为非C#精明的程序员,我对LINQ查询的评估语义感到好奇,如下所示:
1 2 3 4 5 6 7
| var people = FROM p IN Person
WHERE p.age < 18
SELECT p
var otherPeople = FROM p IN people
WHERE p.firstName equals"Daniel"
SELECT p |
假定Person是定义age和firstName字段的ADO实体,从数据库的angular来看,这将做什么?具体来说,是否会运行people查询以生成内存结构,然后由otherPeople查询查询该结构?还是otherPeople的构造只是从people中提取有关查询的数据,然后生成一个新的数据库对等查询?那么,如果我遍历这两个查询,将执行多少个SQL语句?
它们是可组合的。这是可能的,因为LINQ查询实际上是表达式(作为数据的代码),LINQ-to-SQL之类的LINQ提供程序可以评估并生成相应的SQL。
由于LINQ查询的计算是延迟的(例如,直到您遍历元素时才会执行),因此显示的代码实际上不会触及数据库。直到您遍历其他人,否则人们才会生成并执行SQL。
1 2 3
| var people = FROM p IN Person
WHERE p.age < 18
SELECT p |
翻译为:
1 2 3
| SELECT [t0].[PersonId], [t0].[Age], [t0].[FirstName]
FROM [dbo].[Person] AS [t0]
WHERE [t0].[Age] < @p0 |
其中@ p0通过18发送
1 2 3
| var otherPeople = FROM p IN people
WHERE p.firstName equals"Daniel"
SELECT p |
翻译为:
1 2 3
| SELECT [t0].[PersonId], [t0].[Age], [t0].[FirstName]
FROM [dbo].[Person] AS [t0]
WHERE [t0].[FirstName] = @p0 |
其中@ p0以" Daniel"的形式发送通过
1 2 3 4
| var morePeople = FROM p1 IN people
FROM p2 IN otherPeople
WHERE p1.PersonId == p2.PersonId
SELECT p1; |
翻译为:
1 2 3
| SELECT [t0].[PersonId], [t0].[Age], [t0].[FirstName]
FROM [dbo].[Person] AS [t0], [dbo].[Person] AS [t1]
WHERE ([t0].[PersonId] = [t1].[PersonId]) AND ([t0].[Age] < @p0) AND ([t1].[FirstName] = @p1) |
其中@ p0为18,@ p1为"丹尼尔"
如有疑问,请在IQueryable上调用ToString()或将TextWriter赋予DataContext的Log属性。
是的,结果查询已组成。它包含完整的where子句。打开SQL性能分析,然后尝试自己查看。
Linq通过表达式树执行此操作。第一个linq语句产生一个表达式树;它不执行查询。第二个linq语句以第一个创建的表达式树为基础。仅在枚举结果集合时才执行该语句。
people和otherPeople包含类型为IQueryable<Person>的对象。
如果分别对两个对象进行迭代,它将运行两个查询。
如果仅迭代otherPeople,它将运行带有两个where子句的预期查询。
如果对people执行.ToList()并在第二个查询中使用返回的List<Person>而不是人员,则它将成为LINQ-to-Objects,并且不执行SQL。
此行为称为延迟执行。这意味着直到需要查询时才进行查询。在执行之前,它们只是表达式树,它们被操纵以制定最终查询。
当您尝试访问最终结果时,将同时执行这两个查询。您可以尝试查看从DataContext对象属性生成的原始SQL。