[英]Understanding .AsEnumerable() in LINQ to SQL
給出以下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”表被緩存到內存中? 如果表包含大量記錄,這會導致性能下降嗎?
幫助我了解幕后實際發生的事情。
AsEnumerable的原因是
當序列實現IEnumerable(T)但也有一組不同的公共查詢方法時,AsEnumerable(TSource)(IEnumerable(TSource))可用於在查詢實現之間進行選擇
因此,當您之前調用Where
方法時,您正在從IEnumerable.Where
調用另一個Where
方法。 Where
語句用於LINQ轉換為SQL,新的Where
是IEnumerable
獲取IEnumerable
,枚舉它並產生匹配項。 這解釋了為什么您看到生成的不同SQL。 在您的第二版代碼中應用Where
擴展名之前,將從數據庫中完整地獲取該表。 這可能會造成嚴重的瓶頸,因為整個表必須在內存中,或者更糟糕的是整個表必須在服務器之間傳輸。 允許SQL Server執行Where
並執行它最擅長的操作。
在枚舉枚舉的位置,將查詢數據庫,並檢索整個結果集。
零件和零件解決方案可以是方式。 考慮
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>
除了將源的編譯時類型從實現
IEnumerable<T>
的類型更改為IEnumerable<T>
本身之外,AsEnumerable<TSource>(IEnumerable<TSource>)
方法沒有任何效果。
AsEnumerable<TSource>(IEnumerable<TSource>)
可用於在序列實現IEnumerable<T>
時選擇查詢實現,但也可以使用不同的公共查詢方法集。 例如,給定一個實現IEnumerable<T>
並具有自己的方法(如Where
,Select
和SelectMany
的泛型類Table
,對Where
調用將調用Table
的publicWhere
方法。 表示數據庫表的Table
類型可以具有Where
方法,該方法將謂詞參數作為表達式樹並將樹轉換為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的實現。
實體框架不知道如何解釋SomeUnusualPredicate
並不SomeUnusualPredicate
,我的函數將直接使用。 (但是,這可能是一種低效的方法,因為所有行都將從服務器返回。)
我相信AsEnumerable只是告訴編譯器使用哪些擴展方法(在這種情況下是為IEnumerable而不是為IQueryable定義的擴展方法)。 查詢的執行仍然延遲,直到您調用ToArray或枚舉它為止。
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.