1. 程式人生 > >IEnumerable<T>和IQueryable<T>區別

IEnumerable<T>和IQueryable<T>區別

ESS 延遲 indent info ise ons ont 加載 執行

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

看一下vs的Intellisense效果:

技術分享圖片

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

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

第一段代碼效果:

技術分享圖片

第二代碼效果: 技術分享圖片 二者的查詢結果一致,只是前者把查詢參數合並了。

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

現在我們應該知道何時使用IEnumerable<T>,何時使用Iqueryable<T>。建議延遲加載數據使用Iqueryable<T>。

IEnumerable<T>和IQueryable<T>區別