Linq中 AsQueryable(), AsEnumerable()和ToList()的區別和用法:在寫LINQ語句的時候,往往會看到AsEnumerable() ,AsQueryable() 和ToList()的用法,三者有何區別呢?以下是我的理解,有毛病請大家指教!在System.Linq命名 ...
Linq中 AsQueryable(), AsEnumerable()和ToList()的區別和用法:
在寫LINQ語句的時候,往往會看到AsEnumerable() ,AsQueryable() 和ToList()的用法,三者有何區別呢?以下是我的理解,有毛病請大家指教!
在System.Linq命名空間下,有兩個靜態類:
Enumerable類,它針對繼承了IEnumerable<T>介面的集合進行擴展;
Queryable類,針對繼承了IQueryable<T>介面的集合進行擴展。
一、AsQueryable():
先說說什麼是 IQueryable,AsQueryable將一個序列向下轉換為一個IQueryable, 它生成了一個本地查詢的IQueryable包裝。
1,lazy load 特性
以下是一段最常見的代碼:
var products = db.Product.where(p => p.Type == "food").select(p => new { p.Id, p.Name, p.CreateTime});
註意:Select() 的返回類型為 IQueryable,為 IQueryable<T>, 語句執行後不會立刻查詢資料庫, 而是在迭代使用 products 時才會查資料庫, 具有 lazy load 的特性, 按需查資料庫可提高程式效率。
2,高程式效率.
迭代時上面的代碼類似於下麵的 sql 語句:
select Id, Name, CreateTime from Product where Type = 'food'
對 products 再次使用資料庫查詢操作, 運行時會把結果合併為1條 sql 語句, 如下,
var products = db.Product.where(p => p.Type == "food").select(p => new { p.Id, p.Name, p.CreateTime}); var orderedProducts = products.OrderBy(p => p.CreateTime);
迭代時生成的 sql 語句類似:
select Id, Name, CreateTime from Product where Type = 'food' order by CreateTime
IQueryable 有諸多限制, 只支持資料庫查詢語法, 無法支持 Linq to object 的操作, 是LINQ TO SQL。
結論:AsQueryable將一個序列向下轉換為一個IQueryable, 它生成了一個本地查詢的IQueryable包裝。 二、AsEnumerable()
同樣支持 lazy load,是延遲執行的,實際上什麼都沒有發生,當真正使用對象的時候(例如調用:First, Single, ToList....的時候)才執行。 但不要濫用。迭代時遇到 AsEnumerable() 會先進行 sql 查詢, 但是, 千萬不要為了方便而濫用 AsEnumerable(), 可能會嚴重消耗資源,能進行 Linq to object 操作。
eg:var products = db.Product.AsEnumerable().Select(p => new {p.Id, p.Name, p.CreateTime.Date}); 對IQueryable對象使用AsEnumerable()後,仍然是延遲執行,不過此時對象本質已經變了。
上面的代碼在查詢時會把整個Product表的結果存放進記憶體, 然後進行 .Select 查詢,嚴重消耗資源。
結論:AsEnumerable將一個序列向上轉換為一個IEnumerable, 強制將Enumerable類下麵的查詢操作符綁定到後續的子查詢當中。 AsEnumerable()延遲執行,不會立即執行。當你調用.AsEnumerable()的時候,實際上什麼都沒有發生。 註意:IQueryable實現了IEnumberable介面。但IEnumerable<T> 換成IQueryable<T>後速度提高很多。
IQueryable介面與IEnumberable介面的區別: IEnumerable<T> 泛型類在調用自己的SKip 和 Take 等擴展方法之前數據就已經載入在本地記憶體里了,而IQueryable<T> 是將Skip ,take 這些方法表達式翻譯成T-SQL語句之後再向SQL伺服器發送命令,它並不是把所有數據都載入到記憶體里來才進行條件過濾。 三、ToList()
調用 ToList() 會立刻查詢並保存結果, 而不會等到迭代時才查詢,作用和 lazy load 是相反的。
在需要得到完整結果後, 再處理的場景, 需要使用 ToList()。