2009-09-04 29 views
3

ここでは、Customersのリストを返す単純なLINQクエリ(NorthWindベース)を示します。各顧客には注文のリストが含まれています。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を生成します。カスタマーごとに個別の照会が発行されます。あなたは私たちが持っているラムダコードを見てみると:

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 statamentsの原因であるように見えます。しかし、私は成功せずに様々な組み合わせを試みました。何か案は?

編集: 私は達成しようとしていたことについて少し不明なことがありました。 OrderDetailオブジェクトをOrderオブジェクトのプロパティ(Customerオブジェクトのプロパティ)にします。注文& 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

私は元の質問は、彼が単一の結果を望んでいることを意味し、このクエリは、彼が必要とするものを得るために後処理することができることを信じていないがそれぞれの結果に 'OrderDetails'のリストが含まれています。 – jeremyalan

0

あなたは、サーバー上のたOrderDetailsまで参加しようとした後、あなたの完全な階層データ構造を取得するには、クライアント上で「再編成」かもしれません:

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)}