2010-11-18 51 views
0

我使用這樣的SQL來壓扁分層數據。我只是創建一個視圖,並在EF圖上折騰它。但是,這不適合「用LinqPad替換SQL Management Studio」的思路。我將如何在Linq(和C#)中編寫這些代碼? (Linq to Entities/Entity Framework 4)Linq雜技:如何扁化分層數據模型?

表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 

更重要的是,有一個LINQ模式的食譜,你可以查找的SQL,看到了LINQ的相同呢?我已經在C#中看到了101 Linq examples

回答

2

不幸的是,LINQ中既沒有外連接,也不能添加任意連接條件。內部連接可以使用DefaultIfEmpty解決,但是連接條件的Bn.type = n部分需要移動到where條件。

下產生正是你所提供的SQL,除了我所提到的類型的條款:

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

結果

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 

(更新:這是LINQ到SQL,只是假設EF會是類似的。)

Albin的答案更具可讀性,但可能會產生不太理想的SQL。爲了與SQL完全匹配,您需要用DefaultIfEmpty替換FirstOrDefault,儘管(根據您的數據可能沒有區別)。 (對不起,目前還不能評論;-))

+0

小問題 - LINQ本身沒有明確的外連接,但在實體框架中使用LINQ,有很多查詢格式導致外連接 - 例如var people = db.Person.Include(p => p.Address)當Id地址附加時可以爲空 - EF將它解釋爲您的左外連接。 – 2013-11-22 21:30:01

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設計器中創建一些花哨的實體,它可以做到這一點。