2010-11-24 47 views
0

關於下面的查詢的一點背景。細胞有1:M到容器和1:M與打印機。我想要一個查詢,它將檢索所有單元格和關聯的容器(如果它們存在)以及關聯的打印機(如果存在)。基本上我想在兩個表上做一個左外連接。以下是我的查詢:如何在Linq Query中執行多個左外連接?

var query = from cell in Cell 
    join container in Container.Where (row => row.SerialNumber == "1102141") on cell.CellID equals container.CellID 
    into containers 

    join printer in Printer.Where (row => row.Name == "PG10RelWarrPrt3") on cell.CellID equals printer.CellID 
    into printers 

    select new { Cell = cell, Containers = containers, Printers = printers }; 

query.Dump(); 

此查詢有效,但效率不高。它在Container上執行左外連接,但對於每個單元,它執行單獨的查詢來檢索任何Printer行,而不是在Printer上執行左外連接。

我該如何改變它,以便它還在打印機表上進行左外連接?順便說一句,我想要一個分層結果集。 IOW,每個單元應該有一個容器列表和一個打印機列表。當然,如果沒有單元格存在,每個元素都是空的。

+1

http://stackoverflow.com/questions/267488/linq-to-sql-multiple-left-outer-joins – diceguyd30 2010-11-24 13:23:21

+0

@ diceguyd30 - 我看到之前,我發佈我的問題。這並不能解決我的問題。請注意,我聲明我想要一個分層結果集,而不是一個平坦結果集。 DefaultIfEmpty()用於平坦的結果集。 – 2010-11-24 13:28:12

回答

2

下面是產生平坦的結果與正確的左聯接設置查詢。

var query = from cell in Cell 
    join container in Container.Where (row => row.SerialNumber == "1102141") on cell.CellID equals container.CellID 
    into containers 
    from container2 in containers.DefaultIfEmpty() 
    join printer in Printer.Where (row => row.Name == "PG10RelWarrPrt3") on cell.CellID equals printer.CellID 
    into printers 
    from printer2 in printers.DefaultIfEmpty() 
    select new { Cell = cell, Container = container2, Printer = printer2 }; 

您必須在本地後處理結果以獲得所需的分層形狀。

如果你編寫這個後處理代碼,你會明白爲什麼linq to sql不會爲你處理多個兄弟集合。


爲了使這更清晰,假設你有3件兄弟藏品。

如果對於某些父記錄,所有三個兄弟集合都是空的,那麼您將只有一條父母記錄有一個空值。

如果所有三個兄弟集合都有一條父記錄的100條記錄,那麼您將有百萬行,每條記錄都帶有一條父記錄的副本。每個兒童記錄將在結果中重複10,000次。

要記住任何ORM總是很重要的,它會生成sql並獲取平坦的結果集,而不管它最終呈現給您的是什麼層次結構的結果。

1

It's usually wrong to use join in LINQ to SQL

嘗試:

var query = from cell in Cell 
      select new 
      { 
       Cell = cell, 
       Containers = cell.Containers 
           .Where (row => row.SerialNumber == "1102141"), 
       Printers = cell.Printers 
           .Where (row => row.Name == "PG10RelWarrPrt3") 
      };