LINQ to SQL 提供三個 Join 相關 API:
Join:內部聯結(Inner Join)SelectMany:一對多導航屬性聯結(隱式 Left Join)GroupJoin:群組聯結(對應 join ... into)查詢運算式會自動轉換為對應 API。
Join 方法
var q = from c in db.Customers
join o in db.Orders on c.CustomerID equals o.CustomerID
select new { c.CustomerID, o.EmployeeID };
轉換為:
db.Customers.Join(db.Orders,
c => c.CustomerID,
o => o.CustomerID,
(c, o) => new { c.CustomerID, o.EmployeeID });
參數順序固定:外部序列鍵選擇器、內部序列鍵選擇器、結果選擇器。SQL 生成標準 INNER JOIN。
條件:無 join/into 且出現 EntitySet(一對多導航屬性)。
from c in db.Customers
from o in c.Orders // c.Orders 為 EntitySet
where c.City == "London"
select o;
對應映射屬性:
[Association(Name="Order_OrderDetail", Storage="_OrderDetails", OtherKey="OrderID")]
[Association(Name="Order_OrderDetail", Storage="_Order", ThisKey="OrderID", IsForeignKey=true)]
from p in db.Products
where p.Supplier.Country == "USA" && p.UnitsInStock == 0
select p;
生成 SQL 為 LEFT OUTER JOIN Suppliers,最簡潔的 Left Join 寫法。
from e in db.Employees
from et in e.EmployeeTerritories
where e.City == "Seattle"
select new { e.FirstName, e.LastName, et.Territory.TerritoryDescription };
涉及三表 Employees - EmployeeTerritories - Territories,生成 CROSS JOIN + INNER JOIN。
from e1 in db.Employees
from e2 in e1.Employees
where e1.City == e2.City
select new { ... };
生成舊式逗號聯結語法。
GroupJoin 與 join ... into查詢運算式含 join ... into 時轉換為 GroupJoin。
var q = from c in db.Customers
join o in db.Orders on c.CustomerID equals o.CustomerID into orders
select new { c.ContactName, OrderCount = orders.Count() };
into orders 將對應的訂單群組重命名為 orders,可在 select 中呼叫聚合函數。生成 SQL 使用子查詢 SELECT COUNT(*) ...。
join o in db.Orders ... into ords
join e in db.Employees ... into emps
select new { c.ContactName, ords=ords.Count(), emps=emps.Count() };
var q = from e in db.Employees
join o in db.Orders on e equals o.Employee into ords
from o in ords.DefaultIfEmpty()
select new { e.FirstName, e.LastName, Order = o };
join ... into ords 群組聯結from o in ords.DefaultIfEmpty() 展開群組,無對應時產生 nullOrder 為單一物件而非集合生成 SQL 為標準 LEFT OUTER JOIN。
let 子句與 GroupJoin 結合
var q = from c in db.Customers
join o in db.Orders on c.CustomerID equals o.CustomerID into ords
let z = c.City + c.Country
from o in ords
select new { c.ContactName, o.OrderID, z };
let 類似 into 為運算結果重命名,位置可在第一個 from 後、select 前任意處。
join d in db.OrderDetails
on new { o.OrderID, p.ProductID } equals new { d.OrderID, d.ProductID }
into details
使用匿名型別表示複合鍵。