我误解了LINQ to SQL .AsEnumerable()?

Oce*_*t20 49 .net c# linq linq-to-sql

考虑以下代码:

var query = db.Table
              .Where(t => SomeCondition(t))
              .AsEnumerable();

int recordCount = query.Count();
int totalSomeNumber = query.Sum();
decimal average = query.Average();
Run Code Online (Sandbox Code Playgroud)

假设query需要很长时间才能运行.我需要获得记录数,总数SomeNumber已经返回,并在结束时取平均值.我以为根据我读的是.AsEnumerable()将执行使用LINQ到SQL,然后使用LINQ到对象的查询Count,Sum以及Average.相反,当我在LINQPad中执行此操作时,我看到相同的查询运行三次.如果我更换.AsEnumerable().ToList(),它只被查询一次.

我错过了什么AsEnumerable/做什么?

Jus*_*ner 61

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

IQueryable是允许LINQ to SQL执行其魔力的界面.IQueryable实现IEnumerable所以当你调用时AsEnumerable(),你正在改变从那里调用的扩展方法,即从IQueryable-methods到IEnumerable-methods(即在这种特殊情况下从改变LINQ to SQLLINQ to Objects).但是你没有执行实际的查询,只是改变它的整体执行方式.

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

  • 认为"没有真正发生"肯定是不正确的.虽然`AsEnumerable`在调用它时不会对查询进行求值,但它*肯定*有效.对查询进一步调用的任何内容都将使用LINQ to对象进行评估,因此您无法将其他元素组合到查询中(另一个`Where`或`OrderBy`或任何此类性质)将成为SQL语句的一部分. (44认同)
  • 我更喜欢执行相同操作的ToArray,除非您特别需要List <T>实现。 (2认同)
  • @rushonerok`ToList()`更快,所以除非你的对象长期存在,否则使用`ToList`而不是`ToArray`,请参阅http://stackoverflow.com/a/16323412/691294 (2认同)

Ada*_*son 14

是.所有这一切AsEnumerable需要做的是引起Count,SumAverage将要执行的功能的客户端(换句话说,它会带回的整个结果集到客户端,然后在客户端将执行的聚集,而不是建立COUNT() SUM()AVG()SQL语句).

  • @James,贾斯汀:你误解了.我从来没有说'AsEnumerable()`会导致查询评估,我说添加它的唯一事情就是*当*聚合被评估时,它们将在客户端完成(整个结果集将会在客户端*上枚举*,并计算聚合)而不是转换为SQL语句. (9认同)

LCJ*_*LCJ 6

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

我这里只想引用MSDN的解释:.NET Language-Integrated Query for Relational Data

与 ToList() 和 ToArray() 不同,AsEnumerable() 运算符不会导致查询的执行。目前仍被推迟。AsEnumerable() 运算符仅更改查询的静态类型,将 IQueryable 转换为 IEnumerable,欺骗编译器将查询的其余部分视为本地执行。

一旦它是 LINQ to Objects,我们就可以应用对象的方法(例如ToString())。这是有关 LINQ 的常见问题之一的解释 -为什么 LINQ to Entities 无法识别方法“System.String ToString()?”

根据ASENUMERABLE - codeblog.jonskeetAsEnumerable可以方便

最后,另请参阅此相关问题:Returning IEnumerable vs. IQueryable