這個做法在介紹 IEnumerable 與 IQueryable 兩者背後的運作機制,這兩個類型在前幾個做法經常提到,它們專注的方面與運作的效率也差很多。
首先下面這種是用 IQueryableexpression tree
,
最後會翻譯成 SQL 語法傳遞給資料庫運行,所以在進行排序工作的時候是在遠端排序的。
var q = from c in dbContext.Customers
where c.City == "London"
select c;
var finalAnswer = from c in q
orderby c.Name
select c;
另外下面這種是用將上面的程式碼轉成 IEnumerable
var q = (from c in dbContext.Customers
where c.City == "London"
select c).AsEnumerable();
var finalAnswer = from c in q
orderby c.Name
select c;
另外之前也有提到 LINQ to SQL 背後是各種不同的 provider 來進行轉換工作,所以有些時候沒辦法把 C# 的 LINQ 語法轉換成 SQL 的版本, 所以這種時候就只能轉換成 Enumerable 來處理即可。
void Main()
{
private bool isValidProduct(Product p) => p.ProductName.LastIndexOf('C') == 0;
// This works:
var q1 = from p in dbContext.Products.AsEnumerable()
where isValidProduct(p)
select p;
// This throws an exception when you enumerate the collection.
var q2 = from p in dbContext.Products
where isValidProduct(p)
select p;
}
所以關鍵的差異也很好懂,IQueryable
例如在這個例子中把 where 子句移出 IQueryable
var q = (from c in dbContext.Customers
select c).AsEnumerable();
var finalAnswer = from c in q
where c.City == "London"
orderby c.Name
select c;
另外我們可以使用 AsQueryable 方法將一般的 Enumerable 轉換成 Queryable,這樣不管傳入的集合本身是否為 IQueryable
public static IEnumerable<Product> ValidProducts(this IEnumerable<Product> products) =>
from p in products.AsQueryable()
where p.ProductName.LastIndexOf('C') == 0
select p;
Summary
IEnumerable 與 IQueryable 寫起來與看起來基本都相同,但背後運作的機制卻差很多只要記得 IQueryable 背後是透過 provider 進行各種 不同格式的輸出,IEnumerable 則是本地記憶體操作,特別是在使用 EFCore 的時候很有可能沒有注意到目前是 IEnumerable 還是 IQueryable, 一不小心就有可能影響效能。