给出以下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”表被缓存到内存中? 如果表中包含大量记录,这会导致性能下降吗?
帮助我了解幕后实际发生的事情。
答案 0 :(得分:34)
AsEnumerable的原因是
AsEnumerable(TSource)(IEnumerable的(TSource)) 可用于在查询之间进行选择 序列时的实现 实现IEnumerable(T)但也有 一组不同的公共查询 可用的方法
因此,当您之前调用Where
方法时,您从Where
调用了另一个IEnumerable.Where
方法。 Where
语句用于LINQ转换为SQL,新Where
是IEnumerable
语句,它接受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>
并拥有自己的方法,例如Where
,Select
和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或枚举它之前,查询的执行仍会延迟。