我误解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到对象的Count
, Sum
Average
。 相反,当我在LINQPad中这样做时,我看到相同的查询运行了三次。 如果我用.AsEnumerable()
replace.ToList()
,它只会被查询一次。
我错过了什么AsEnumerable
什么?
调用AsEnumerable(
)不执行查询,枚举它。
IQueryable
是允许LINQ to SQL
执行其魔术的接口。 IQueryable
实现IEnumerable
所以当你调用AsEnumerable()
,你正在改变从那里调用的扩展方法,即从IQueryable
-methods到IEnumerable
-methods(即在这个特例中从LINQ to SQL
到LINQ to Objects
)。 但是你并没有执行实际的查询,只是改变了整个执行的过程。
要强制查询执行,您必须调用ToList()
。
是。 AsEnumerable
所要做的就是使Count
, Sum
和Average
函数在客户端执行(换句话说,它会将整个结果集带回到客户端,然后客户端将执行这些聚合,而不是创buildCOUNT()
SUM()
和AVG()
语句)。
那么,你在正确的轨道上。 问题是一个IQueryable
( AsEnumerable
调用之前的语句)也是一个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意味着在执行计算的代码调用数据之前不会获取数据。 我猜这是因为数据库被命中三次 – 每次计算一次,数据不会被保存到内存中。