我误解LINQ to SQL .AsEnumerable()?

考虑这个代码:

var query = db.Table .Where(t => SomeCondition(t)) .AsEnumerable(); int recordCount = query.Count(); int totalSomeNumber = query.Sum(); decimal average = query.Average(); 

假设query需要很长时间才能运行。 我需要得到logging数,总SomeNumber返回,并在最后取平均值。 我想基于我的阅读.AsEnumerable()将使用LINQ到SQL执行查询,然后使用LINQ到对象的CountSum Average 。 相反,当我在LINQPad中这样做时,我看到相同的查询运行了三次。 如果我用.AsEnumerable()replace.ToList() ,它只会被查询一次。

我错过了什么AsEnumerable什么?

调用AsEnumerable( )不执行查询,枚举它。

IQueryable是允许LINQ to SQL执行其魔术的接口。 IQueryable实现IEnumerable所以当你调用AsEnumerable() ,你正在改变从那里调用的扩展方法,即从IQueryable -methods到IEnumerable -methods(即在这个特例中从LINQ to SQLLINQ to Objects )。 但是你并没有执行实际的查询,只是改变整个执行的过程。

要强制查询执行,您必须调用ToList()

是。 AsEnumerable所要做的就是使CountSumAverage函数在客户端执行(换句话说,它会将整个结果集带回到客户端,然后客户端将执行这些聚合,而不是创buildCOUNT() SUM()AVG()语句)。

那么,你在正确的轨道上。 问题是一个IQueryableAsEnumerable调用之前的语句)也是一个IEnumerable ,所以这个调用实际上是一个nop。 这将需要强制它到一个特定的内存数据结构(例如, ToList() )来强制查询。

贾斯汀尼斯纳的回答是完美的。

我只想在这里引用一个MSDN解释: 关系数据的.NET语言集成查询

与ToList()和ToArray()不同,AsEnumerable()运算符不会导致执行查询。 它仍然推迟。 AsEnumerable()运算符只是改变查询的静态types,把IQueryable变成IEnumerable,诱使编译器将查询的其余部分视为本地执行。

我希望这是什么意思:

IQueryable方法的IEnumerable方法(即从LINQ到SQL到LINQ到对象

一旦它是LINQ到对象,我们可以应用对象的方法(例如ToString() )。 这是关于LINQ的一个常见问题的解释 – 为什么LINQ to Entities不能识别方法System.String ToString()?

根据ASENUMERABLE – codeblog.jonskeet , AsEnumerable下可以得心应手:

在数据库中查询的一些方面,然后在.NET中进行更多的操作 – 特别是如果有些方面你基本上不能在LINQ to SQL(或者你正在使用的任何提供者)中实现。

它还说:

我们所做的只是将通过查询从IQueryable传播到IEnumerable的序列的编译时间types,但这意味着编译器将使用Enumerable中的方法(将委托并在LINQ中执行到对象)在Queryable中(使用expression式树,通常是执行out-of-process)。

最后,也看到这个相关的问题: 返回IEnumerable与IQueryable

我会假定ToList强制Linq从数据库中获取logging。 然后,当您执行前面的计算时,他们是针对内存对象而不是涉及数据库的。

将返回types保留为Enumerable意味着在执行计算的代码调用数据之前不会获取数据。 我猜这是因为数据库被命中三次 – 每次计算一次,数据不会被保存到内存中。