我昨天遇到一個LINQ下使用多條件比對產生LEFT JOIN的問題,經過深入研究,終於解決了,也讓我學到了新的東西,特地拿來分享。
實例:有一張庫存異常變更視圖KCYD,倉庫ID[Ckid]和物品ID[SpxxId]是該視圖的唯一約束。有一張物品表ITEM,物品ID[ITEM_ID]是主鍵。還有一張表是統計正品和次品庫存數量的視圖SPKC,倉庫ID[CKID]和物品ID[SPXXID]是該視圖的唯一約束。現在的要求是根據條件查詢庫存異常變更的物品信息,即要求KCYD左聯ITEM再左聯SPKC。KCYD和ITEM的公共字段是物品ID,KCYD和SPKC的公共字段是倉庫ID和物品ID。
我原先想到的寫法如下:
var query = from k in DBContext.KCYD
join i in DBContext.ITEM
on k.SPXXID equals i.ITEM_ID into g
from gc in g.DefaultIfEmpty()
join s in DBContext.SPKC
on k.SpxxId equals s.SPXXID into g1
from gc1 in g1.DefaultIfEmpty()
where k.Ckid == gc1.CKID
select new
{
... ...
};
但是生成的SQL語句,KCYD和ITEM表是LEFT OUTER JOIN的,但是聯SPKC表卻變成了INNER JOIN,這是為啥呢,經過一番折騰下來,發現問題出在where k.Ckid == gc1.CKID,如果把這個條件去掉的話,那就成了LEFT OUTER JOIN了,然後我就在想這個條件應該放在哪呢,LINQ裡面到底支不支持聯合主鍵的問題呢,在網上搜了半天,發現可以用 on new {字段1,字段2} equals new {字段1,字段2} into g的方法,於是修改代碼如下:
var query = from k in DBContext.KCYD
join i in DBContext.ITEM
on k.SPXXID equals i.ITEM_ID into g
from gc in g.DefaultIfEmpty()
join s in DBContext.SPKC
on new {k.SpxxId,k.Ckid} equals new {s.SPXXID,s.CKID} into g1
from gc1 in g1.DefaultIfEmpty()
select new
{
... ...
};
但是很不給力的是這樣居然提示錯誤:The type arguments cannot be inferred from the query.
簡直就是杯具,難道LINQ不支持這樣搞?唉,在我絕望的時候同事為我看出了端倪,原來equals兩邊的參數字段名的大小寫必須完全匹配。即完整代碼如下:
var query = from k in DBContext.KCYD
join i in DBContext.ITEM
on k.SPXXID equals i.ITEM_ID into g
from gc in g.DefaultIfEmpty()
join s in DBContext.SPKC
on new {SPXXID=k.SpxxId,CKID=k.Ckid} equals new {s.SPXXID,s.CKID} into g1
from gc1 in g1.DefaultIfEmpty()
select new
{
... ...
};
大功告成!