LINQ查詢中的IEnumerable 和IQueryable


LINQ查詢方法一共提供了兩種擴展方法,在System.Linq命名空間下,有兩個靜態類:Enumerable類,它針對繼承了IEnumerable<T>接口的集合進行擴展;Queryable類,針對繼承了IQueryable<T>接口的集合進行擴展。我們會發現接口IQueryable<T>實際也是繼承了IEnumerable<T>接口的,既然這樣微軟為什么要設計出兩套擴展方法呢?

從LINQ查詢功能上我們知道實際上可以分為三類:LINQ to OBJECTS、LINQ to SQL和LINQ to XML。其實微設計這兩套接口主要是針對LINQ to OBJECTS和LINQ to SQL,兩者對於查詢的內部處理機制是完全不同的。針對LINQ to OBJECTS 時,使用Enumerable中的擴展方法對本地集合進行排序和查詢操作,查詢參數接受的是Func<>,Func<>叫做謂語表達式,相當於一個委托。針對LINQ to SQL時,則使用Queryable中的擴展方法,它接受的是Expression<>。

那么,到底什么時候使用IQueryable<T>,什么時候使用IEnumerable<T>?

首先我們來看一下LINQ to SQL的代碼:

using (var context = new NorthwindEntities())

{

var orderTmp = context.Orders.Where(p=>p.CustomerID=="RATTC");

var orders = orderTmp.Where(p => p.OrderDate > new DateTime(1997, 1, 1));

foreach (var order in orders)

{

Console.WriteLine("OrderId:" + order.OrderID);

}

}

 

通過vs的Intellisense我們可以看到Where的返回類型為IQueryable,參數是Expression類型的:

 

我們再看一下這一段代碼:

using (var context = new NorthwindEntities())

{

var orderTmp = context.Orders.Where(p => p.CustomerID == "RATTC").AsEnumerable();

var orders = orderTmp.Where(p => p.OrderDate > new DateTime(1997, 1, 1));

foreach (var order in orders)

{

Console.WriteLine("OrderId:" + order.OrderID);

}

}

 

這段代碼的不同在於我們將LINQ的查詢返回IEnumerable類型,我們看一下vs的Intellisense效果:

由於我們在LINQ查詢的時候加上了AsEnumerable(),因此我們在第二條語句能看到返回類型已經變為IEnumerable,參數也變成了Func<>類型。

至於這兩段代碼到底有什么區別,我們分別執行代碼,在sql profiler里看一下生成的sql語句:

第一段代碼效果:

雖然我們使用兩條語句進行了查詢,但最終只生成了一條SQL語句,將查詢參數合並了。

第二代碼效果:

這一次我們依然只看到一條SQL語句,但查詢條件也只有一個,但兩次查詢的結果是一致。

 

原因在於Func<>直接會被編譯器編譯成IL代碼,但是Expression<>只是存儲了一個表達式樹,在運行期作處理,LINQ to SQL最終會將表達式樹轉為相應的SQL語句,然后在數據庫中執行

現在我們應該知道何時使用IEnumerable<T>,何時使用Iqueryable<T>。

 

以上內容部分參考《編寫高質量代碼改善C#程序的157個建議》。


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM