(使用实体框架)
我写的时候:
IEnumerable<string> q = customers /*EF entity*/
.Select (c => c.Name.ToUpper())
.OrderBy (n => n)
c#编译器知道如何发出表达式树,而sql又执行:
SELECT UPPER (Name) FROM Customer ORDER BY UPPER (Name)
还注意到order by
子句在那里
但
我看到 this link :
他写道:IEnumerable<employee> emp =
dc.Employees.Where(x => x.Desc.StartsWith("soft"));
emp = emp.Take(1);
在调查最终查询后,他看到了:
SELECT [t0].[Id], [t0].[Name], [t0].[Address], [t0].[Desc] AS [Desc]
FROM [dbo].[Employee] AS [t0]
WHERE [t0].[Desc] LIKE @p0
注意没有 top
子句
为什么会这样?
不应该Take(x)
添加到查询中吗?
会像这样写:
IEnumerable<employee> emp =
(dc.Employees.Where(x => x.Desc.StartsWith("soft"))).Take(1);
会将TOP子句添加到发送给SQL的查询吗?
这是怎么回事?
(我已经知道take
不是延迟执行)
答案 0 :(得分:9)
如果您将Take(1)
添加到第一个表达式,它将在IQueryable<T>
上,从而添加到SQL中。但是,自从您将IQueryable<T>
转换为IEnumerable<T>
后,Take(1)
在内存中完成:IEnumerable<T>
具有相同名称的Take()
extension method,并且就编译器而言,{ {1}}为emp
,而不是IEnumerable<T>
,因此会调用内存中的版本。
答案 1 :(得分:5)
Take()
等扩展方法是静态方法,因此它们在编译时解析。
emp的编译时类型是IEnumerable<employee>
(因为它显式声明为1),因此编译器选择Enumerable.Take
而不是Queryable.Take
,它不执行任何查询转换。
如果您一直懒惰,只使用 var
而不是类型名称:
var emp = dc.Employees.Where(x => x.Desc.StartsWith("soft"));
emp = emp.Take(1);
它会起作用,因为编译器会为emp选择IQueryable<employee>
(因为你初始化它的表达式是那个类型),因此第二次调用Queryable.Take
。