簡體   English   中英

理解LINQ to SQL中的.AsEnumerable()

[英]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,新的WhereIEnumerable獲取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>並具有自己的方法(如WhereSelectSelectMany的泛型類Table ,對Where調用將調用Table的public Where方法。 表示數據庫表的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.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM