2009-09-04 90 views
3

這是一個簡單的LINQ查詢(基於NorthWind),它返回一個Customers列表。每個客戶都包含訂單列表。LINQ中的分層查詢

from c in Customers 
join o in Orders on c.CustomerID equals o.CustomerID into CO 
select new {c, CO} 

這工作正常,生成的SQL也很好。現在我想更進一步。我希望每個Order對象都包含一個OrderDetails列表。我正在使用以下查詢:

from c in Customers 
join od in (
    from o in Orders 
    join od in OrderDetails on o.OrderID equals od.OrderID into OD 
    select new { o.CustomerID, o, OD } 
) 
on c.CustomerID equals od.CustomerID into COD 
select new { c, COD } 

此查詢工作但生成可怕的SQL。爲每個客戶發出單獨的查詢。當你看看我們的lambda代碼:

Customers 
    .GroupJoin (
     Orders 
     .GroupJoin (
      OrderDetails, 
      o => o.OrderID, 
      od => od.OrderID, 
      (o, OD) => 
       new 
       { 
        CustomerID = o.CustomerID, 
        o = o, 
        OD = OD 
       } 
     ), 
     c => c.CustomerID, 
     od => od.CustomerID, 
     (c, COD) => 
     new 
     { 
      c = c, 
      COD = COD 
     } 
    ) 

嵌套的GroupJoins似乎是多個SQL狀態的原因。但是,我嘗試過各種組合,但沒有成功。有任何想法嗎?

編輯: 我可能一直不清楚我想達到的目標。我希望OrderDetail對象是Order對象的屬性,它又是Customer對象的屬性。我不希望Order & OrderDetail是Customer的屬性。我正在嘗試獲取獨特客戶的名單。對於每個客戶,我期望訂單清單,並且對於每個訂單,我需要一個OrderDetails清單。我希望層次結構比我的原始查詢更深入一層。

回答

0

爲什麼不直接使用多個聯接:

from c in Customers 
join o in Orders on c.CustomerID equals o.CustomerID 
join od in OrderDetails on o.OrderID equals od.OrderID 
select new {c, o, od} 
+0

雖然我不相信這個查詢可以進行後處理,以得到他所需要的,原來的問題意味着他想要一個結果per'Customer',其中每個結果都包含一個'OrderDetails'列表。 – jeremyalan 2009-09-04 17:59:08

0

你可以嘗試加入到服務器上的訂單明細,然後在客戶端上「重組」,讓您充分分層數據結構:

var q = from c in Customers 
     join o in Orders on c.CustomerID equals o.CustomerID 
     join od in OrderDetails on o.OrderID equals od.OrderID into OD 
     select new { c, o, OD }; 

var res = from x in q.AsEnumerable() 
      group x by x.c.CustomerID into g 
      select new 
      { 
       Customer = g.First().c, 
       Orders = g.Select(y => new 
         { 
          Order = y.o, 
          OrderDetails = y.OD 
         }) 
      }; 
1

如果要強制單個查詢,那麼你可以對服務器端對客戶端沒有分組:

from a in (from c in Customers 
    join o in Orders on c.CustomerID equals o.CustomerID 
    join od in OrderDetails on o.OrderID equals od.OrderID 
    select new {c, o, od}).AsEnumerable() 
group a by a.c into g 
select new { Customer = g.Key, Orders = g.Select(o => o.o) , OrderDetails = g.Select(od => od.od)} 

生成的SQL是:

SELECT [t0].[CustomerID], [t0].[CompanyName], [t0].[ContactName], [t0].[ContactTitle], [t0].[Address], [t0].[City], [t0].[Region], [t0].[PostalCode], [t0].[Country], [t0].[Phone], [t0].[Fax], [t1].[OrderID], [t1].[CustomerID] AS [CustomerID2], [t1].[EmployeeID], [t1].[OrderDate], [t1].[RequiredDate], [t1].[ShippedDate], [t1].[ShipVia], [t1].[Freight], [t1].[ShipName], [t1].[ShipAddress], [t1].[ShipCity], [t1].[ShipRegion], [t1].[ShipPostalCode], [t1].[ShipCountry], [t2].[OrderID] AS [OrderID2], [t2].[ProductID], [t2].[UnitPrice], [t2].[Quantity], [t2].[Discount] 
FROM [Customers] AS [t0] 
INNER JOIN [Orders] AS [t1] ON [t0].[CustomerID] = [t1].[CustomerID] 
INNER JOIN [Order Details] AS [t2] ON [t1].[OrderID] = [t2].[OrderID] 

熊記住這是而不是快於多個查詢,同時它增加了網絡和服務器的負載。

我的建議是使用像查詢以下內容:

DataLoadOptions opt = new DataLoadOptions(); 
opt.LoadWith<Orders>(o => o.OrderDetails); 
this.LoadOptions = opt; 

from c in Customers 
select new {c, Orders = c.Orders, OrderDetails = c.Orders.SelectMany(o=> o.OrderDetails)}