关于C#:我是否误解了linq to sql.aseNumerable()?

Am I misunderstanding LINQ to SQL .AsEnumerable()?

考虑此代码:

1
2
3
4
5
6
7
var query = db.Table
              .Where(t => SomeCondition(t))
              .AsEnumerable();

int recordCount = query.Count();
int totalSomeNumber = query.Sum();
decimal average = query.Average();

假设query运行时间很长。我需要得到记录计数,返回的SomeNumber的总数,并在最后取一个平均值。根据我的阅读,我认为.AsEnumerable()将使用linq to sql执行查询,然后使用linq to objects来执行CountSumAverage的查询。相反,当我在LinqPad中执行此操作时,我看到相同的查询运行了三次。如果我用.ToList()替换.AsEnumerable(),只查询一次。

我是否遗漏了一些关于AsEnumerable是/做的事情?


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

IQueryable是允许LINQ to SQL执行其魔法的接口。IQueryable实现IEnumerable,所以当您调用AsEnumerable()时,您将更改从那里调用的扩展方法,即从IQueryable方法更改为IEnumerable方法(在本例中,从LINQ to SQL更改为LINQ to Objects)。但您并没有执行实际的查询,只是更改了整个查询的执行方式。

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


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


好吧,你走对了。问题是,一个IQueryable(在AsEnumerable调用之前的语句)也是一个IEnumerable,因此该调用实际上是一个nop。它需要强制它使用特定的内存数据结构(例如,ToList()来强制查询。


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

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

The AsEnumerable() operator, unlike ToList() and ToArray(), does not cause execution of the query. It is still deferred. The AsEnumerable() operator merely changes the static typing of the query, turning a IQueryable into an IEnumerable, tricking the compiler into treating the rest of the query as locally executed.

我希望这就是所谓的:

IQueryable-methods to the IEnumerable-methods (ie changing from LINQ to SQL to LINQ to Objects

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

根据AsEnumerable-codeblog.jonsket的说法,在以下情况下,AsEnumerable可以很方便:

some aspects of the query in the database, and then a bit more manipulation in .NET – particularly if there are aspects you basically can’t implement in LINQ to SQL (or whatever provider you’re using).

它还说:

All we’re doing is changing the compile-time type of the sequence which is propagating through our query from IQueryable to IEnumerable – but that means that the compiler will use the methods in Enumerable (taking delegates, and executing in LINQ to Objects) instead of the ones in Queryable (taking expression trees, and usually executing out-of-process).

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


我假设ToList强制Linq从数据库中获取记录。然后,当您执行继续计算时,它们是针对内存中的对象执行的,而不是涉及数据库。

将返回类型保留为可枚举的意味着在执行计算的代码调用它之前,不会提取数据。我想这其中的附带作用是数据库被命中三次——每次计算一次,数据不会持久保存到内存中。