LINQ 提供平行的雙重架構:
IEnumerable<T>,使用 Enumerable 操作符,以委托執行。IQueryable<T>,使用 Queryable 操作符,以表達式樹在執行時解析並轉譯(如 SQL)。.NET 內建兩大 IQueryable 實作:LINQ to SQL 與 LINQ to Entities。AsQueryable() 可將任何可列舉集合包裝為 IQueryable。
以查詢包含 "a" 的客戶名稱為例:
var query = from c in customers
where c.Name.Contains("a")
orderby c.Name.Length
select c.Name.ToUpper();
編譯器先轉為 Lambda 語法,再解析操作符。因 customers 為 Table<Customer>(實作 IQueryable),編譯器選擇 Queryable.Where,其簽名接受 Expression<Func<T, bool>>,導致 Lambda 被解析為表達式樹而非委托。LINQ to SQL 隨後將表達式樹翻譯為 SQL:
SELECT UPPER([Name]) FROM [Customer] WHERE [Name] LIKE '%a%' ORDER BY LEN([Name])
解釋查詢同樣遵循延遲執行:只有列舉時才產生 SQL。重複列舉會重複查詢資料庫,需注意效能。執行時,外層序列會走訪整棵表達式樹並一次性翻譯為單一 SQL 陳述式。
與本地查詢不同,擴展 IQueryable 極為困難:自訂擴展方法無法被遠端提供者理解,會導致與特定提供者綁定,失去互通性。此外,某些 LINQ 標準操作可能無法翻譯為 SQL,視資料庫而定。
AsEnumerable() 將 IQueryable 轉為 IEnumerable,強制後續操作在本地執行。例如資料庫不支援 Regex,可先篩選主題再本地過濾內容:
var query = dataContext.Articles
.Where(a => a.Topic == "LINQ")
.AsEnumerable()
.Where(a => reg.Matches(a.Content).Count > 500);
優於 ToList() 之處在於保持延遲執行且不建立中間集合。