IEnumerable <t>和Take(x)问题?</t>

时间:2012-06-22 13:32:59

标签: c# .net linq entity-framework .net-4.0

(使用实体框架)

我写的时候:

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不是延迟执行)

2 个答案:

答案 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