LinqToEntities erzeugt falsches SQL (doppelte Unterabfrage)

Ich habe eine LinqToEntities-Abfrage, die eine Unterabfrage doppelt erzeugt, wenn SQL erstellt wird. Dies führt dazu, dass die Ergebnismenge jedes Mal, wenn die Abfrage ausgeführt wird, mit 0-3 Ergebnissen zurückkommt. Die Unterabfrage alleine erzeugt ein einziges randomes Ergebnis (wie es sollte). Was geht hier vor sich?

Die LINQ-Abfrage:

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 } 

Erzeuge dieses 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) 

BEARBEITEN:

Das Ändern der Unterabfrage funktioniert also, aber ich habe keine Ahnung warum

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

Solutions Collecting From Web of "LinqToEntities erzeugt falsches SQL (doppelte Unterabfrage)"

Dies FirstOrDefault() aufgrund des erwarteten Verhaltens von FirstOrDefault() . Das Aufrufen von FirstOrDefault() für eine leere Menge von JobProviderJobs würde einen null erzeugen, aber das Aufrufen von FirstOrDefault() für eine leere Menge von int S würde eine 0 . LINQ to Entities versucht, am Ende der Abfrage eine case-statement aufzurufen, um sicherzustellen, dass das Ergebnis der Auswahl 0 ist, wenn keine passenden JobProviderJobs vorhanden sind.

In den meisten Fällen würde das NewGuid() der inneren Projektion keine Probleme verursachen, aber die Verwendung von NewGuid() diese Logik offensichtlich aus.

Du hast eine Lösung gefunden. Ein anderer wäre, das Ergebnis des inneren Ausdrucks so zu wirken:

 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 } 

Eine korrektere Implementierung würde die anfängliche SQL-Projektion wiederverwenden, anstatt zwei äquivalente Projektionen zu erstellen. Es ist wahrscheinlich, dass der Parser einfach nicht komplex genug ist, um dies richtig zu handhaben, und die Entwickler sahen nie eine Notwendigkeit, dies zu beheben, da SQL server in der Lage sein sollte, die identischen Projektionen so lange zu optimieren, wie sie deterministisch sind.

Sie sollten wahrscheinlich einen Fehlerbericht darüber protokollieren, wenn dieser noch nicht existiert.