了解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语句中缺lesswhere子句。
这是否意味着整个“导入”表被caching到内存? 如果表中包含大量的logging,这是否会降低性能?
帮助我了解幕后的实际情况。
AsEnumerable的原因是
当一个序列实现IEnumerable(T)时,AsEnumerable(TSource)(IEnumerable(TSource))可以用于在查询实现之间进行select,但是也有一组不同的公共查询方法
所以当你在调用Where方法之前,你正在从IEnumerable.Where调用一个不同的Where方法。 Where语句用于LINQ转换为SQL,新的Where是IEnumerable接受IEnumerable的枚举,枚举它并生成匹配的项目。 这就解释了为什么你看到不同的SQL正在生成。 在扩展名将被应用到你的第二个版本的代码之前,表将从数据库中完整地获取。 这可能造成严重的瓶颈,因为整个表必须在内存中,或者更糟的是整个表必须在服务器之间传送。 允许SQL服务器执行Where,并执行它最擅长的操作。
在枚举枚举的地方,数据库将被查询,并检索整个结果集。
一个零件的解决scheme可以是这样的。 考虑
 var res = ( from result in SomeSource where DatabaseConvertableCriterion(result) && NonDatabaseConvertableCriterion(result) select new {result.A, result.B} ); 
我们还要说,NonDatabaseConvertableCriterion需要结果字段C. 因为NonDatabaseConvertableCriterion的名字就是这么做的,所以这个必须作为一个枚举来执行。 但是,请考虑:
 var partWay = ( from result in SomeSource where DatabaseConvertableCriterion(result) select new {result.A, result.B, result.C} ); var res = ( from result in partWay.AsEnumerable() where NonDatabaseConvertableCriterion select new {result.A, result.B} ); 
在这种情况下,当res被枚举,查询或以其他方式使用时,尽可能多的工作将被传递给数据库,这将返回足够的时间来继续工作。 假设确实不可能重写,所有的工作都可以发送到数据库,这可能是一个合适的妥协。
 有三个AsEnumerable实现。 
 DataTableExtensions.AsEnumerable 
 扩展一个DataTable给它一个IEnumerable接口,所以你可以使用Linq对DataTable 。 
  Enumerable.AsEnumerable<TSource>和ParallelEnumerable.AsEnumerable<TSource> 
除了将源的编译时types从实现
IEnumerable<T>的types更改为IEnumerable<T>本身之外,AsEnumerable<TSource>(IEnumerable<TSource>)方法无效。当一个序列实现
IEnumerable<T>时,AsEnumerable<TSource>(IEnumerable<TSource>)可以用来在查询实现之间进行select,但也可以使用不同的公共查询方法。 例如,如果给定一个实现了IEnumerable<T>的generics类Table,并且拥有自己的方法(如Where,Select和SelectMany,则调用Where将调用Table的PublicWhere方法。 表示数据库表的Tabletypes可以有一个Where方法,它将谓词参数作为expression式树并将树转换为SQL以供远程执行。 如果不需要远程执行,例如因为谓词调用本地方法,则可以使用AsEnumerable<TSource>方法来隐藏自定义方法,而是使标准查询运算符可用。
换一种说法。
如果我有一个
 IQueryable<X> sequence = ...; 
从一个LinqProvider,像entity framework,而我呢,
 sequence.Where(x => SomeUnusualPredicate(x)); 
 该查询将被组成并在服务器上运行。 这将在运行时失败,因为EntityFramework不知道如何将SomeUnusualPredicate转换为SQL。 
如果我想要用Linq来运行声明而不是对象,
 sequence.AsEnumerable().Where(x => SomeUnusualPredicate(x)); 
 现在服务器将返回所有数据,并且将使用从Linq到Objects的Enumerable.Where而不是Query Provider的实现。 
 entity framework不知道如何解释SomeUnusualPredicate并不SomeUnusualPredicate ,我的函数将直接使用。  (但是,这可能是一种效率低下的方法,因为所有的行将从服务器返回。) 
我相信AsEnumerable只是告诉编译器使用哪些扩展方法(在这种情况下是为IEnumerable而不是IQueryable定义的)。 查询的执行仍然是延迟,直到您调用ToArray或枚举它。