了解 LINQ to SQL 中的 .AsEnumerable()

发布于 2024-09-11 07:56:55 字数 758 浏览 4 评论 0原文

给定以下 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 子句。

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

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

Given the following LINQ to SQL query:

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

The interpreted SQL statement is:

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

Say I wanted to perform some action in the select that cannot be converted to SQL. Its my understanding that the conventional way to accomplish this is to do AsEnumerable() thus converting it to a workable object.

Given this updated code:

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

And updated SQL:

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

Notice the lack of a where clause in the executed SQL statement.

Does this mean the entire "Imports" table is cached into memory?
Would this slow performance at all if the table contained a large amount of records?

Help me to understand what is actually happening behind the scenes here.

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(4

可爱暴击 2024-09-18 07:56:55

AsEnumerable 的原因是

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

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

The reason for AsEnumerable is to

AsEnumerable(TSource)(IEnumerable(TSource))
can be used to choose between query
implementations when a sequence
implements IEnumerable(T) but also has
a different set of public query
methods available

So when you were calling the Where method before, you were calling a different Where method from the IEnumerable.Where. That Where statement was for LINQ to convert to SQL, the new Where is the IEnumerable one that takes an IEnumerable, enumerates it and yields the matching items. Which explains why you see the different SQL being generated. The table will be taken in full from the database before the Where extension will be applied in your second version of the code. This could create a serious bottle neck, because the entire table has to be in memory, or worse the entire table would have to travel between servers. Allow SQL server to execute the Where and do what it does best.

想你的星星会说话 2024-09-18 07:56:55

在枚举完成后,将查询数据库,并检索整个结果集。

部分解决方案可能是一种方法。考虑

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 时,尽可能多的工作将传递到数据库,数据库将返回足够的内容来继续作业。假设确实不可能重写以便将所有工作发送到数据库,这可能是一个合适的折衷方案。

At the point where the enumeration is enumerated through, the database will then be queried, and the entire resultset retrieved.

A part-and-part solution can be the way. Consider

var res = (
    from result in SomeSource
    where DatabaseConvertableCriterion(result)
    && NonDatabaseConvertableCriterion(result)
    select new {result.A, result.B}
);

Let's say also that NonDatabaseConvertableCriterion requires field C from result. Because NonDatabaseConvertableCriterion does what its name suggests, this has to be performed as an enumeration. However, consider:

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}
);

In this case, when res is enumerated, queried or otherwise used, as much work as possible will be passed to the database, which will return enough to continue the job. Assuming that it is indeed really impossible to rewrite so that all the work can be sent to the database, this may be a suitable compromise.

早乙女 2024-09-18 07:56:55

AsEnumerable 共有三种实现。

DataTableExtensions.AsEnumerable

扩展 DataTable 以为其提供 IEnumerable 接口,以便您可以针对 DataTable 使用 Linq

Enumerable.AsEnumerable< ;TSource>ParallelEnumerable.AsEnumerable

AsEnumerable(IEnumerable) 方法无效
除了将源的编译时类型更改为
IEnumerable 实现为 IEnumerable 本身。

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

换句话说。

如果我有一个

IQueryable<X> sequence = ...;

来自 LinqProvider(例如实体框架)的查询,那么

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

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

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

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

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

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

There are three implementations of AsEnumerable.

DataTableExtensions.AsEnumerable

Extends a DataTable to give it an IEnumerable interface so you can use Linq against the DataTable.

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

The AsEnumerable<TSource>(IEnumerable<TSource>) method has no effect
other than to change the compile-time type of source from a type that
implements IEnumerable<T> to IEnumerable<T> itself.

AsEnumerable<TSource>(IEnumerable<TSource>) can be used to choose
between query implementations when a sequence implements
IEnumerable<T> but also has a different set of public query methods
available. For example, given a generic class Table that implements
IEnumerable<T> and has its own methods such as Where, Select, and
SelectMany, a call to Where would invoke the public Where method of
Table. A Table type that represents a database table could have a
Where method that takes the predicate argument as an expression tree
and converts the tree to SQL for remote execution. If remote execution
is not desired, for example because the predicate invokes a local
method, the AsEnumerable<TSource> method can be used to hide the
custom methods and instead make the standard query operators
available.

In other words.

If I have an

IQueryable<X> sequence = ...;

from a LinqProvider, like Entity Framework, and I do,

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

that query will be composed and run on the server. This will fail at runtime because the EntityFramework doesn't know how to convert SomeUnusualPredicate into SQL.

If I want that to run the statement with Linq to Objects instead, I do,

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

now the server will return all the data and the Enumerable.Where from Linq to Objects will be used instead of the Query Provider's implementation.

It won't matter that Entity Framework doesn't know how to interpret SomeUnusualPredicate, my function will be used directly. (However, this may be an inefficient approach since all rows will be returned from the server.)

守护在此方 2024-09-18 07:56:55

我相信 AsEnumerable 只是告诉编译器要使用哪些扩展方法(在本例中是为 IEnumerable 定义的扩展方法,而不是为 IQueryable 定义的扩展方法)。
查询的执行仍然会延迟,直到您调用 ToArray 或对其进行枚举。

I believe the AsEnumerable just tells the compiler which extension methods to use (in this case the ones defined for IEnumerable instead of those for IQueryable).
The execution of the query is still deferred until you call ToArray or enumerate on it.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文