2010-05-15 46 views
2

我有一個LINQ查詢,由於某種原因正在生成額外/重複的INNER JOIN。這導致查詢不返回預期的輸出。如果我從生成的SQL手動註釋該額外的JOIN,那麼我得到看似正確的輸出。LINQ認爲我需要一個額外的INNER JOIN,但是爲什麼?

你可以檢測到我可能在這個LINQ中做了什麼導致這個額外的JOIN?

謝謝。

這是我約LINQ

predicate=predicate.And(condition1); 
predicate1=predicate1.And(condition2); 
predicate1=predicate1.And(condition3); 
predicate2=predicate2.Or(predicate1); 
predicate=predicate.And(predicate2); 
var ids = context.Code.Where(predicate); 
      var rs = from r in ids 
        group r by r.PersonID into g 
        let matchcount=g.Select(p => p.phonenumbers.PhoneNum).Distinct().Count() 
        where matchcount ==2 
        select new 
        { 
         personid = g.Key 
        }; 

,這裏是生成的SQL(重複連接是[T7])

Declare @p1 VarChar(10)='Home' 
Declare @p2 VarChar(10)='111' 
Declare @p3 VarChar(10)='Office' 
Declare @p4 VarChar(10)='222' 
Declare @p5 int=2 

SELECT [t9].[PersonID] AS [pid] 
FROM (
    SELECT [t3].[PersonID], (
     SELECT COUNT(*) 
     FROM (
      SELECT DISTINCT [t7].[PhoneValue] 
      FROM [dbo].[Person] AS [t4] 
      INNER JOIN [dbo].[PersonPhoneNumber] AS [t5] ON [t5].[PersonID] = [t4].[PersonID] 
      INNER JOIN [dbo].[CodeMaster] AS [t6] ON [t6].[Code] = [t5].[PhoneType] 
      INNER JOIN [dbo].[PersonPhoneNumber] AS [t7] ON [t7].[PersonID] = [t4].[PersonID] 
      WHERE ([t3].[PersonID] = [t4].[PersonID]) AND ([t6].[Enumeration] = @p0) AND ((([t6].[CodeDescription] = @p1) AND ([t5].[PhoneValue] = @p2)) OR (([t6].[CodeDescription] = @p3) AND ([t5].[PhoneValue] = @p4))) 
      ) AS [t8] 
     ) AS [value] 
    FROM (
     SELECT [t0].[PersonID] 
     FROM [dbo].[Person] AS [t0] 
     INNER JOIN [dbo].[PersonPhoneNumber] AS [t1] ON [t1].[PersonID] = [t0].[PersonID] 
     INNER JOIN [dbo].[CodeMaster] AS [t2] ON [t2].[Code] = [t1].[PhoneType] 
     WHERE ([t2].[Enumeration] = @p0) AND ((([t2].[CodeDescription] = @p1) AND ([t1].[PhoneValue] = @p2)) OR (([t2].[CodeDescription] = @p3) AND ([t1].[PhoneValue] = @p4))) 
     GROUP BY [t0].[PersonID] 
     ) AS [t3] 
    ) AS [t9] 
WHERE [t9].[value] = @p5 
+0

哪個是額外JOIN? – 2010-05-15 11:46:01

+0

INNER JOIN [dbo]。[PersonPhoneNumber] AS [t5] ON [t5]。[PersonID] = [t4]。[PersonID]和 INNER JOIN [dbo]。[PersonPhoneNumber] AS [t7] ON [t7]。 [PersonID] = [t4]。[PersonID],所以[t7]是一個dublicate。 – 2010-05-15 11:51:53

回答

0

他們沒有被複制。您正在從數據源中請求兩個不同的值。

let matchcount=g.Select(p => p.phonenumbers.PhoneNum).Distinct().Count() 

導致

 SELECT COUNT(*) 
     FROM ( 
      SELECT DISTINCT [t7].[PhoneValue] 
      FROM [dbo].[Person] AS [t4] 
      INNER JOIN [dbo].[PersonPhoneNumber] AS [t5] ON [t5].[PersonID] = [t4].[PersonID] 
      INNER JOIN [dbo].[CodeMaster] AS [t6] ON [t6].[Code] = [t5].[PhoneType] 
      INNER JOIN [dbo].[PersonPhoneNumber] AS [t7] ON [t7].[PersonID] = [t4].[PersonID] 
      WHERE ([t3].[PersonID] = [t4].[PersonID]) AND ([t6].[Enumeration] = @p0) AND ((([t6].[CodeDescription] = @p1) AND ([t5].[PhoneValue] = @p2)) OR (([t6].[CodeDescription] = @p3) AND ([t5].[PhoneValue] = @p4))) 
      ) AS [t8] 

     from r in ids 
        group r by r.PersonID into g 

導致

SELECT [t0].[PersonID]  
    FROM [dbo].[Person] AS [t0]  
    INNER JOIN [dbo].[PersonPhoneNumber] AS [t1] ON [t1].[PersonID] = [t0].[PersonID]  
    INNER JOIN [dbo].[CodeMaster] AS [t2] ON [t2].[Code] = [t1].[PhoneType]  
    WHERE ([t2].[Enumeration] = @p0) AND ((([t2].[CodeDescription] = @p1) AND ([t1].[PhoneValue] = @p2)) OR (([t2].[CodeDescription] = @p3) AND ([t1].[PhoneValue] = @p4)))  
    GROUP BY [t0].[PersonID]  
    ) AS [t3] 

作爲內部連接,你讓他們的理由是,因爲關係在這些表格之間。例如,Person是1..1的PersonPhoneNumber(或1 .. *)。在這兩種情況下,我都假設PersonPhoneNumber上的PersonID是FK和PK值。因此,在這種情況下,數據源必須出到該外部表以查看PersonPhoneNumber導航屬性的值是否實際存在。它通過在該表上執行INNER JOIN來完成此操作。

0

我的直覺是,.DISTINCT()。COUNT ()由linq to sql翻譯分開處理。

我還打賭SQL上的執行計劃只是拋出了這個謎團。

0

嘗試用明確的條件來重寫,而不是抽象的「謂詞」構造。從我在SQL中看到,組合對孤立的解析器可能看起來很奇怪,並且有一個連接[t5],你可以稱它爲笨蛋:-)來滿足這個條件。

另外,試着告訴我們你真的想用這個查詢找到什麼樣的技巧,然後嘗試編寫正常的SQL來做你想做的事。我應該是人類的:-),它對我來說也很奇怪:-))

從技術上講,你通過在兩個單獨的查詢中使用in的條件來強制雙關節(每個var分配它在技術上是分開的查詢)。

另外做一個沒有做任何聚合的列並不總是相當於選擇不同。特別是,選擇不同的連接可以優先於連接 - 查詢是聲明性的(可以進行重新排序),並且您試圖強制它是程序性的。所以,LINQ給了你確切的程序:-)然後SQL按照SQL規則重新排序:-))

所以,只要先寫正常的SQL,如果你不能LINQ-ize它把它放入sproc - 它會無論如何使它更快:-)

相關問題