2011-08-01 54 views
0

我需要連接兩個對象(表格)A和B.對於任何A,可以有多個B到零。該查詢需要每A返回一行。如何使用Linq執行「複雜」連接

B我想在連接之前訂購,以便能夠根據特定條件從B中選擇所需的行。說B有一個列類型。如果有類型1,那麼這就是我需要的B,如果不是的話:類型2必須被選中,等等。

現在我考慮一下,我不知道我會如何去T-sql。 我覺得是這樣的:

SELECT A.* 
FROM A LEFT JOIN (
    SELECT * FROM B AS B1 WHERE B1.Type = (SELECT TOP 1 B2.Type FROM B AS B2 
             WHERE B2.JoinID = B1.JoinID 
             ORDER BY B2.Type) 
) AS B ON B.JoinID = A.JoinID 

[編輯]

隨着sgtz的答案我試圖使其工作。如果因爲我想訂購的字段不存在而必須再做一個步驟。我在步驟1中添加此字段,在步驟2中,我選擇了鍵並在步驟3中加入了所有內容,但在那裏收到錯誤「join子句中的某個表達式的類型不正確。對'GroupJoin'的呼叫。「關於加入「在新的{b.TopRelatieID adressen1加入......」

var adressen1 = from a in db.Adres 
        select new 
        { 
         RelatieAdres = a, 
         Sortering = (int)(a.AdresType.Code == codeVestAdres ? 
              1 : a.AdresType.Code == codePostAdres ? 
               2 : (100 + (int)a.AdresType.Code.ToCharArray()[0])) 
        }; 

    var adressen2 = from b in adressen1 
        group b by new { RelatieID = b.RelatieAdres.RelatieID } into p 
        let TopAdresType = p.Min(at => at.Sortering) 
        select new { TopRelatieID = p.Key.RelatieID, TopAdresType }; 

    var q = from k in db.Klants 
      join b in adressen2 on k.RelatieID equals b.TopRelatieID into b_join 
      from b in b_join.DefaultIfEmpty() 
      join a in adressen1 on new { b.TopRelatieID, b.TopAdresType } equals new { a.RelatieAdres.RelatieID, a.Sortering } into a_join 
      from a in a_join.DefaultIfEmpty() 
+0

使用這個查詢,你只會返回A中所有的行,每個行只有一次或多次,因爲有來自B的行,它們與那行相連並滿足你的WHERE條件,這看起來很奇怪。 .. –

+0

@Stefan:爲你發佈了一個答案。 – sgtz

+0

@MichaelSagalovich這聽起來很奇怪,但如果我解釋目的是什麼,那不是。 A =客戶和B =地址。我希望所有的客戶只有一個地址,這將是住房地址,如果存在,否則帳單地址,否則... –

回答

0

這是一個成功的例子。我做了兩個階段。

[Test] 
    public void Test333() 
    { 
     List<Order> O; 
     var M = Prepare333Data(out O); 

     var OTop = from o in O 
        group o by new {id=o.id, orderid=o.orderid} 
        into p 
        let topType = p.Min(tt => tt.type) 
        select new Order(p.Key.id, p.Key.orderid, topType); 

     var ljoin = from m in M 
        join t in OTop on m.id equals t.id into ts 
        from u in ts.DefaultIfEmpty() 
        select new {u.id, u.orderid, u.type}; 
    } 

    public class Manufacturer 
    { 
     public Manufacturer(int id, string name) 
     { 
      this.id = id; 
      this.name = name; 
     } 

     public int id { get; set; } 
     public string name { get; set; } 
    } 

    public class Order 
    { 
     public Order(int id, int orderid, int type) 
     { 
      this.orderid = orderid; 
      this.id = id; 
      this.type = type; 
     } 

     public int orderid { get; set; } 
     public int id { get; set; } 
     public int type { get; set; } 
    } 


    private List<Manufacturer> Prepare333Data(out List<Order> O) 
    { 
     var M = new List<Manufacturer>() {new Manufacturer(1, "Abc"), new Manufacturer(2, "Def")}; 
     O = new List<Order>() 
       { 
        new Order(1, 1, 2), 
        new Order(1, 2, 2), 
        new Order(1, 2, 3), 
        new Order(2, 3, 1) 
        , 
        new Order(2, 3, 1) 
        , 
        new Order(2, 3, 2) 
       }; 
     return M; 
    } 

迴應評論:

你的 「新{」 創建一個新的匿名類型。如果類型按照相同順序聲明並且它們具有相同的類型定義(即int匹配int,而不是int匹配short),那麼差異進程創建的兩個匿名類型被稱爲具有相同的簽名。我還沒有在LINQ中廣泛地測試過這個場景。

這就是爲什麼我使用真正的具體類,而不是在JOIN部分內的匿名類型。可能有一種方法可以用純LINQ重做它,但我不知道那是還是。如果發生在我身上,我會發布回覆。

我建議現在也使用具體的類。即
代替

*new {* 

做連接,始終使用

*new CLASSNAME(){prop1="abc",prop2="123"* 

這是一個長一點,但更安全......更安全時,至少直到我們制定出什麼是LINQ裏面怎麼回事內部。

+0

酷,這有助於很多。有一件事:我怎麼會得到B的其他成員(在你的例子中是O)?此示例僅檢索組合鍵加上最小類型,但我如何獲得其他成員? –

+0

我認爲這是「SELECT TOP 1 ... ORDER BY ...」所做的。你想要哪些其他成員 - 所有這些成員? – sgtz

+0

對不起,看起來不太好。你的解決方案很好! –

0

有意義,你應該至少添加東西的查詢結果,不僅A. *。否則,你將得到一份A的副本,其中一些行可能重複。如果我理解正確的問題,這個SQL查詢應該工作:

SELECT DISTINCT A.*, B.Type 
FROM A LEFT JOIN 
(SELECT TOP (1) JoinID, Type 
FROM B 
ORDER BY Type 
GROUP BY JoinID, Type 
) AS B ON A.JoinID = B.JoinID 

翻譯成LINQ,它是(修訂

(from a in As 
join b in 
(from b1 in Bs 
orderby b1.Type 
group b1 by b1.JoinID into B1 
from b11 in B1 
group b11 by b11.Type into B11 
from b111 in B11 
select new { b111.JoinID, b111.Type }).Take(1) 
on a.JoinID equals b.JoinID into a_b 
from ab in a_b.DefaultIfEmpty()    
select new { a_b.JoinID, /*all other a properties*/ a_b.Type }).Distinct() 

LINQ可能無法正常工作100%正確,但你應該抓住這個想法。

+0

這將導致多種組合A和B這不是我正在尋找。我只需要一個記錄A和一個(或零)記錄B. –

+0

@Stefan我忘了TOP 1,對不起。糾正。 –