2010-11-18 9 views
0

私はこのようにSQLを使用して階層データを平坦化します。私はビューを作成し、それをEF図に投げるだけです。しかし、これは "SQL Management StudioをLinqPadで置き換える"という考え方に合わない。私はLinq(とC#)でこれらをどのように記述しますか? (Linq to Entities/Entity Framework 4)Linq Acrobatics:hieraricalデータモデルをどのように平坦化するのですか?

テーブルAは製品を保持し、テーブルBは多くの種類のカテゴリを保持します。私は、ビューで単一のフィールドとして、カテゴリIDを選択します:

select A.*, B1.category as color, B2.category as size, B3.category as shape 
from A left join B B1 on A.key = B1.key and B1.type = 1 -- Selects one B row 
     left join B B2 on A.key = B2.key and B2.type = 2 
     left join B B3 on A.key = B3.key and B3.type = 3 

いっそのこと、あなたはSQLをアップ見て、LINQの同等物を見ることができますLINQのパターンの料理はありますか?私は既にC#で101 Linq examplesを見ました。

答えて

2

残念ながら、LINQに外部結合がなく、任意の結合条件を追加することもできません。内部結合はDefaultIfEmptyを使用して行うことができますが、結合条件のBn.type = n部分はwhere条件に移動する必要があります。

以下は、私が言及したタイプの条項を除いて、あなたが提供する正確にSQLを生成します:

exec sp_executesql N'SELECT [t0].[key], [t1].[category] AS [color], [t2].[category] AS [size], [t3].[category] AS [shape] 
FROM [Product] AS [t0] 
LEFT OUTER JOIN [Category] AS [t1] ON [t0].[key] = [t1].[key] 
LEFT OUTER JOIN [Category] AS [t2] ON [t0].[key] = [t2].[key] 
LEFT OUTER JOIN [Category] AS [t3] ON [t0].[key] = [t3].[key] 
WHERE ([t1].[type] = @p0) AND ([t2].[type] = @p1) AND ([t3].[type] = @p2)',N'@p0 int,@p1 int,@p2 int',@p0=1,@p1=2,@p2=3 

from A in products 
join B1 in categories on A.key equals B1.key into tmp_color 
join B2 in categories on A.key equals B2.key into tmp_size 
join B3 in categories on A.key equals B3.key into tmp_shape 
from B1 in tmp_color.DefaultIfEmpty() 
from B2 in tmp_size.DefaultIfEmpty() 
from B3 in tmp_shape.DefaultIfEmpty() 
where B1.type == 1 && B2.type == 2 && B3.type == 3 
select new { product = A, color = B1.category, size = B2.category, shape = B3.category }; 

結果(更新:それはちょうどEFがあろうと仮定して、SQLにLINQです類似しているかもしれません。)

アルビンの答えは読みやすく、おそらく最適ではないSQLを生成します。あなたのSQLと完全に一致するには、FirstOrDefaultをDefaultIfEmptyに置き換える必要があります(データに応じて違いはありません)。 (申し訳ありませんが、まだコメントできません;-))

+0

マイナーポイント - LINQ自体に明示的な外部結合はありませんが、Entity FrameworkでLINQを使用すると、外部結合につながるクエリ形式がたくさんあります。 var people = db.Person.Include(p => p.Address)は、IdアドレスがアタッチされているときにNULLを許可します - EFはこれを左外部ジョインとして解釈します。 –

2

私は副選択アプローチに行きます。

from a in ModelEntities.A 
select new 
{ 
    f1 = a.f1, 
    f2 = a.f2, 
    // ..., 
    fn = a.fn, 
    color = ModelEntities.B.Where(b => a.key == b.key && b.type == 1) 
          .Select(b => b.category).FirstOrDefault(), 
    size = ModelEntities.B.Where(b => a.key == b.key && b.type == 2) 
          .Select(b => b.category).FirstOrDefault(), 
    shape = ModelEntities.B.Where(b => a.key == b.key && b.type == 3) 
          .Select(b => b.category).FirstOrDefault(), 
} 

しかし、ビューの習慣を作成した後は、おそらくEFデザイナーにこのような何かをする必要があります。

関連する問題