2012-06-29 89 views
6

我有一個LinqToEntities查詢,在創建SQL時會產生一個子查詢。這會導致結果集返回0-3結果,每次查詢運行。子查詢本身會產生一個隨機結果(因爲它應該)。這裏發生了什麼?LinqToEntities生成不正確的SQL(加倍子查詢)

LINQ查詢:

from jpj in JobProviderJobs 
where jpj.JobID == 4725 
&& jpj.JobProviderID == (from jp2 in JobProviderJobs 
         where jp2.JobID == 4725 
         orderby Guid.NewGuid() 
         select jp2.JobProviderID).FirstOrDefault() 
select new 
{ 
    JobProviderID = jpj.JobProviderID 
} 

產生這種SQL:

SELECT 
[Filter2].[JobID] AS [JobID], 
[Filter2].[JobProviderID1] AS [JobProviderID] 
FROM (SELECT [Extent1].[JobID] AS [JobID], [Extent1].[JobProviderID] AS [JobProviderID1], [Limit1].[JobProviderID] AS [JobProviderID2] 
    FROM [dbo].[JobProviderJob] AS [Extent1] 
    LEFT OUTER JOIN (SELECT TOP (1) [Project1].[JobProviderID] AS [JobProviderID] 
     FROM (SELECT 
      NEWID() AS [C1], 
      [Extent2].[JobProviderID] AS [JobProviderID] 
      FROM [dbo].[JobProviderJob] AS [Extent2] 
      WHERE 4725 = [Extent2].[JobID] 
     ) AS [Project1] 
     ORDER BY [Project1].[C1] ASC) AS [Limit1] ON 1 = 1 
    WHERE 4725 = [Extent1].[JobID]) AS [Filter2] 
LEFT OUTER JOIN (SELECT TOP (1) [Project2].[JobProviderID] AS [JobProviderID] 
    FROM (SELECT 
     NEWID() AS [C1], 
     [Extent3].[JobProviderID] AS [JobProviderID] 
     FROM [dbo].[JobProviderJob] AS [Extent3] 
     WHERE 4725 = [Extent3].[JobID] 
    ) AS [Project2] 
    ORDER BY [Project2].[C1] ASC) AS [Limit2] ON 1 = 1 
WHERE [Filter2].[JobProviderID1] = (CASE WHEN ([Filter2].[JobProviderID2] IS NULL) THEN 0 ELSE [Limit2].[JobProviderID] END) 

編輯:

因此改變子查詢到這個工作,但我不知道爲什麼

(from jp2 in JobProviderJobs 
    where jp2.JobID == 4725 
    orderby Guid.NewGuid() 
    select jp2).FirstOrDefault().JobProviderID 

回答

3

這是由於預期的行爲FirstOrDefault()。在一組空JobProviderJobs上調用FirstOrDefault()將產生一個null值,但在空集ints上調用該值將產生0。認識到這一點,LINQ to Entities嘗試在查詢結束時調用case語句,以確保如果沒有匹配的JobProviderJobs,則select的結果將爲0而不是null。

在大多數情況下,重新創建內部投影不會導致任何問題,但使用NewGuid()顯然會拋出此邏輯。

您找到了一個解決方案。另一個將是投內表達正是如此的結果:

from jpj in JobProviderJobs 
where jpj.JobID == 4725 
&& jpj.JobProviderID == (from jp2 in JobProviderJobs 
         where jp2.JobID == 4725 
         orderby Guid.NewGuid() 
         select (int?) jp2.JobProviderID).FirstOrDefault() 
select new 
{ 
    JobProviderID = jpj.JobProviderID 
} 

更正確執行將重新使用初始SQL投影,而不是創建兩個等效的突起。解析器很可能不夠複雜,無法正確處理此問題,開發人員也從未發現需要修復它,因爲SQL Server應該能夠優化相同的投影,只要它們是確定性的。

如果不存在,您應該記錄一個關於此的錯誤報告。

+1

希望我能加3,完美的答案:行爲,解決方案的說明,並使用單詞「正是如此」的=) – Tyrsius

+0

@Tyrsius:我有[成功](http://connect.microsoft.com/VisualStudio/feedback/details/658392/linq-to-entities-order by-is-lost-when-after-first-first-default)在[Visual Studio和.NET]下記錄錯誤(https://connect.microsoft.com/VisualStudio/反饋) – StriplingWarrior