首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
您现在的位置: 程式碼之家 >> 數據庫知識 >  >> SQL Server 資料庫 >> 關於SqlServer

LINQ 學習筆記:Join 與 GroupJoin 完整指南 (三) - Lookup 機制、ToLookup 手工優化與等價性

     編輯:關於SqlServer

Join/GroupJoin 在 LINQ to Objects 內部採用**兩階段機制**:建立 Lookup → 合併外部序列。理解 ILookup 可手工優化重複連接、實現自訂連接邏輯。

ILookup 介面定義


public interface ILookup : IEnumerable>, IEnumerable {
    int Count { get; }
    bool Contains(TKey key);
    IEnumerable this[TKey key] { get; } // 索引器:鍵 → 元素序列
}
  • **分組序列字典**:每個鍵對應**多個元素** (vs IDictionary 單一值)。
  • **唯讀、不可變**:建立後不支援增刪改。

ToLookup:手工建立查找表


// 將所有購買單依 CustomerID 建立 Lookup
ILookup purchLookup = purchases
    .ToLookup(p => p.CustomerID, p => p); 
// 參數 1: keySelector | 參數 2: elementSelector (可省略,預設為元素本身)

Lookup 讀取與枚舉


// 索引器回傳匹配元素序列 (非單一元素)
foreach (var p in purchLookup[1]) { // 客戶 ID = 1 的所有訂單
    Console.WriteLine(p.Description);
}

// 不存在鍵回傳空序列 (不拋出例外)
var empty = purchLookup[999]; // Empty IEnumerable

Lookup 等價於 Join / GroupJoin 的手工實現

1. SelectMany + Lookup = Join (內連接)


var q = from c in customers
        from p in purchLookup[c.ID]          // 直接索引查找
        select new { c.Name, p.Description, p.Price };
// 效能與 Join 相同,適用於**多次重用同一 Lookup** 的場景

2. SelectMany + DefaultIfEmpty + Lookup = 左外連接 (扁平)


var q = from c in customers
        from p in purchLookup[c.ID].DefaultIfEmpty()
        select new {
            c.Name,
            Descript = p == null ? null : p.Description,
            Price = p == null ? (decimal?)null : p.Price
        };

3. Select + Lookup = GroupJoin (層級)


var q = from c in customers
        select new {
            CustName = c.Name,
            CustPurchases = purchLookup[c.ID] // 直接取得群組序列
        };

實務優化場景:重複連接同一內部集合


// 場景:多個查詢都需連接 purchases
var purchLookup = purchases.ToLookup(p => p.CustomerID);

// 查詢 1:高價值訂單客戶
var q1 = from c in customers
         from p in purchLookup[c.ID]
         where p.Price > 1000
         select c.Name;

// 查詢 2:最近訂單客戶
var q2 = from c in customers
         from p in purchLookup[c.ID]
         where p.Date > DateTime.Now.AddDays(-30)
         select c.Name;

// 查詢 3:GroupJoin 風格報表
var q3 = from c in customers
         select new { c.Name, Orders = purchLookup[c.ID] };
手工 ToLookup 將「建立雜湊表」與「連接邏輯」分離,**避免重複建立查找表**,適合同一內部集合被多次連接的批次報表/分析查詢。

總結:連接策略選擇決策樹

  1. LINQ to SQL / Entity Framework: 直接使用查詢運算式 join/GroupJoin,翻譯為 SQL JOIN,資料庫優化器處理,**無需手工 Lookup**。
  2. LINQ to Objects (本地集合):
    • 單次連接 → 查詢運算式 join (自動優化)。
    • 同一內部集合**多次連接** → 手工 ToLookup 快取,後續用 SelectMany/Select 索引。
    • 需**非等值連接/交叉連接** → 僅能用 SelectMany + where。
  1. 上一篇文章:
  2. 下一篇文章:
Copyright © 程式碼之家 All Rights Reserved