理解LINQ to SQL中的.AsEnumerable()

时间:2010-07-22 16:48:20

标签: c# linq linq-to-sql asenumerable

给出以下LINQ to SQL查询:

var test = from i in Imports
           where i.IsActive
           select i;

解释的SQL语句是:

SELECT [t0].[id] AS [Id] .... FROM [Imports] AS [t0] WHERE [t0].[isActive] = 1

假设我想在select中执行一些无法转换为SQL的操作。我的理解是,实现这一目标的传统方法是AsEnumerable()将其转换为可行的对象。

鉴于此更新代码:

var test = from i in Imports.AsEnumerable()
           where i.IsActive
           select new 
           { 
               // Make some method call 
           };

更新了SQL:

SELECT [t0].[id] AS [Id] ... FROM [Imports] AS [t0] 

注意执行的SQL语句中缺少where子句。

这是否意味着整个“Imports”表被缓存到内存中? 如果表中包含大量记录,这会导致性能下降吗?

帮助我了解幕后实际发生的事情。

4 个答案:

答案 0 :(得分:34)

AsEnumerable的原因是

  

AsEnumerable(TSource)(IEnumerable的(TSource))   可用于在查询之间进行选择   序列时的实现   实现IEnumerable(T)但也有   一组不同的公共查询   可用的方法

因此,当您之前调用Where方法时,您从Where调用了另一个IEnumerable.Where方法。 Where语句用于LINQ转换为SQL,新WhereIEnumerable语句,它接受IEnumerable,枚举它并生成匹配项。这解释了为什么您看到生成的不同SQL。在您的第二版代码中应用Where扩展名之前,将从数据库中完整地获取该表。这可能会造成严重的瓶颈,因为整个表必须在内存中,或者更糟糕的是整个表必须在服务器之间传输。允许SQL服务器执行Where并执行它最擅长的操作。

答案 1 :(得分:6)

答案 2 :(得分:5)

AsEnumerable有三种实现。

<强> DataTableExtensions.AsEnumerable

扩展DataTable以提供IEnumerable界面,以便您可以将Linq用于DataTable

Enumerable.AsEnumerable<TSource>ParallelEnumerable.AsEnumerable<TSource>

  

AsEnumerable<TSource>(IEnumerable<TSource>)方法无效   除了从类型更改源代码的编译时类型   实现IEnumerable<T>IEnumerable<T>本身。

     

AsEnumerable<TSource>(IEnumerable<TSource>)可用于选择   在序列实现时的查询实现之间   IEnumerable<T>但也有一组不同的公共查询方法   可用。例如,给定实现的泛型类Table   IEnumerable<T>并拥有自己的方法,例如WhereSelect和   SelectMany,对Where的调用会调用公共Where方法   Table。表示数据库表的Table类型可以具有   将谓词参数作为表达式树的Where方法   并将树转换为SQL以进行远程执行。如果远程执行   不需要,例如因为谓词调用本地   方法,AsEnumerable<TSource>方法可用于隐藏   自定义方法,而是制作标准查询运算符   可用。

换句话说。

如果我有

IQueryable<X> sequence = ...;
来自LinqProvider的

,比如Entity Framework,我做了,

sequence.Where(x => SomeUnusualPredicate(x));

该查询将在服务器上编写并运行。这将在运行时失败,因为EntityFramework不知道如何将SomeUnusualPredicate转换为SQL。

如果我希望用Linq to Objects运行语句,我会这样做,

sequence.AsEnumerable().Where(x => SomeUnusualPredicate(x));

现在服务器将返回所有数据,并且将使用从Linq到Objects的Enumerable.Where而不是查询提供程序的实现。

实体框架不知道如何解释SomeUnusualPredicate并不重要,我的功能将直接使用。 (但是,这可能是一种效率低下的方法,因为所有行都将从服务器返回。)

答案 3 :(得分:2)

我相信AsEnumerable只是告诉编译器使用哪些扩展方法(在这种情况下是为IEnumerable而不是为IQueryable定义的扩展方法)。 在您调用ToArray或枚举它之前,查询的执行仍会延迟。