2009-01-29 78 views
28

我有一個左外部聯接(下圖),按預期返回結果。我需要將'右'表的結果限制爲'第一'命中。我能以某種方式做到嗎?目前,我得到了兩張表中每條記錄的結果,但我只想從左側的表格(項目)看到一個結果,而不管在右側表格(照片)中有多少結果。如何將LINQ左外部聯接限制爲一行

 var query = from i in db.items 
       join p in db.photos 
       on i.id equals p.item_id into tempPhoto 
       from tp in tempPhoto.DefaultIfEmpty() 
       orderby i.date descending 
       select new 
       { 
        itemName = i.name, 
        itemID = i.id, 
        id = i.id, 
        photoID = tp.PhotoID.ToString() 
       }; 


    GridView1.DataSource = query; 
    GridView1.DataBind(); 

回答

51

這將爲你做這項工作。

from i in db.items 
let p = db.photos.Where(p2 => i.id == p2.item_id).FirstOrDefault() 
orderby i.date descending 
select new 
{ 
    itemName = i.name, 
    itemID = i.id, 
    id = i.id, 
    photoID = p == null ? null : p.PhotoID.ToString(); 
} 

我得到這個SQL時,我產生了對我自己的模型(並沒有名稱和投影中的第二個id列)。

SELECT [t0].[Id] AS [Id], CONVERT(NVarChar,(
    SELECT [t2].[PhotoId] 
    FROM (
     SELECT TOP (1) [t1].[PhotoId] 
     FROM [dbo].[Photos] AS [t1] 
     WHERE [t1].[Item_Id] = ([t0].[Id]) 
     ) AS [t2] 
    )) AS [PhotoId] 
FROM [dbo].[Items] AS [t0] 
ORDER BY [t0].[Id] DESC 

當我問了這個計劃,它表明,子查詢此連接實現的:

<RelOp LogicalOp="Left Outer Join" PhysicalOp="Nested Loops"> 
+0

我喜歡這個解決方案的優雅,但我認爲這可能會創建一個查詢,因爲子選擇,SQL更難以優化 – 2009-01-29 18:04:57

+0

我對生成的SQL和預計的執行計劃都進行了檢查並感到滿意。該子選擇被計劃爲左外連接。 – 2009-01-29 18:15:28

3

你想要做什麼是組表。要做到這一點,最好的辦法是:

var query = from i in db.items 
       join p in (from p in db.photos 
          group p by p.item_id into gp 
          where gp.Count() > 0 
          select new { item_id = g.Key, Photo = g.First() }) 
      on i.id equals p.item_id into tempPhoto 
      from tp in tempPhoto.DefaultIfEmpty() 
      orderby i.date descending 
      select new 
      { 
       itemName = i.name, 
       itemID = i.id, 
       id = i.id, 
       photoID = tp.Photo.PhotoID.ToString() 
      }; 

編輯:這是大衛乙說。我只是這樣做,因爲尼克問我。尼克,請根據您的意願修改或刪除此部分。

生成的SQL非常大。 int 0(與計數進行比較)通過參數傳入。

SELECT [t0].X AS [id], CONVERT(NVarChar(MAX),(
    SELECT [t6].Y 
    FROM (
     SELECT TOP (1) [t5].Y 
     FROM [dbo].[Photos] AS [t5] 
     WHERE (([t4].Y IS NULL) AND ([t5].Y IS NULL)) OR (([t4].Y IS NOT NULL) AND ([t5].Y IS NOT NULL) AND ([t4].Y = [t5].Y)) 
     ) AS [t6] 
    )) AS [PhotoId] 
FROM [dbo].[Items] AS [t0] 
CROSS APPLY ((
     SELECT NULL AS [EMPTY] 
     ) AS [t1] 
    OUTER APPLY (
     SELECT [t3].Y 
     FROM (
      SELECT COUNT(*) AS [value], [t2].Y 
      FROM [dbo].[Photos] AS [t2] 
      GROUP BY [t2].Y 
      ) AS [t3] 
     WHERE (([t0].X) = [t3].Y) AND ([t3].[value] > @p0) 
     ) AS [t4]) 
ORDER BY [t0].Z DESC 

執行計劃顯示三個左連接。至少有一個是微不足道的,不應該被計算在內(它會帶來零)。這裏有足夠的複雜性,我不能清楚地指出任何問題的效率。它可能運行得很好。

2

你可以這樣做:

var q = from c in 
      (from s in args 
      select s).First() 
     select c; 

大約在查詢的最後一部分。不知道它是否會工作或它會產生什麼樣的奇怪的SQL :)