了解 LINQ to SQL 中的 .AsEnumerable()
-
27-09-2020 - |
题
给定以下 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 子句。
这是否意味着整个“导入”表都缓存到内存中?如果表包含大量记录,性能会降低吗?
帮助我了解幕后实际发生的事情。
解决方案
的原因 作为可枚举的 是为了
可调(tsource)(iEnumerable(tsource))可用于在查询实现之间进行选择,当序列实现iEnumerable(t),但也具有不同的公共查询方法
所以当你打电话给 Where
之前的方法,你调用了不同的 Where
方法从 IEnumerable.Where
. 。那 Where
语句用于将 LINQ 转换为 SQL,新的 Where
是个 IEnumerable
一个需要一个 IEnumerable
, ,枚举它并生成匹配项。这解释了为什么您会看到生成不同的 SQL。该表将在执行之前从数据库中完整获取 Where
扩展将应用于您的第二个版本的代码中。这可能会造成严重的瓶颈,因为整个表必须位于内存中,或者更糟糕的是,整个表必须在服务器之间传输。允许SQL服务器执行 Where
并做它最擅长的事情。
其他提示
在枚举枚举的位置,然后将验证数据库,并检索整个结果集。
部分和部分解决方案可以是方式。考虑
var res = (
from result in SomeSource
where DatabaseConvertableCriterion(result)
&& NonDatabaseConvertableCriterion(result)
select new {result.A, result.B}
);
.
让我们也可以说NondatabaseConvertableSigerion需要Field C.因为NondatabaseConvertableSeCerion是它的名字所建议的,因此必须作为枚举执行。但是,考虑:
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>
这
AsEnumerable<TSource>(IEnumerable<TSource>)
方法除了从实现的类型中更改编译时源外,没有其他效果IEnumerable<T>
到IEnumerable<T>
本身。
AsEnumerable<TSource>(IEnumerable<TSource>)
可以使用序列实施时在查询实现之间进行选择IEnumerable<T>
但也有不同的公共查询方法。例如,给定一个泛型类Table
实现IEnumerable<T>
并且有自己的方法,例如Where
,Select
, , 和SelectMany
, ,致电Where
会呼吁公众Where
的方法Table
. 。ATable
表示数据库表的类型可以有Where
将谓词参数作为表达树并将树转换为SQL以进行远程执行的方法。例如,如果不需要远程执行,例如,因为谓词调用了本地方法,则AsEnumerable<TSource>
方法可用于隐藏自定义方法,而是使标准查询运算符可用。
换句话说。
如果我有一个
IQueryable<X> sequence = ...;
来自 LinqProvider,例如实体框架,我这样做,
sequence.Where(x => SomeUnusualPredicate(x));
该查询将在服务器上编写并运行。这将在运行时失败,因为 EntityFramework 不知道如何转换 SomeUnusualPredicate
进入 SQL。
如果我希望使用 Linq to Objects 来运行该语句,我会这样做,
sequence.AsEnumerable().Where(x => SomeUnusualPredicate(x));
现在服务器将返回所有数据和 Enumerable.Where
将使用 Linq to Objects 来代替查询提供程序的实现。
实体框架不知道如何解释也没关系 SomeUnusualPredicate
, ,我的函数将直接使用。(但是,这可能是一种低效的方法,因为所有行都将从服务器返回。)
我相信Asenuble只是告诉编译器要使用的扩展方法(在这种情况下为IEnumerable定义的,而不是iQueryable)。 在调用toArray或枚举之前,仍会延迟查询的执行。