2013-08-26 8 views
12

Ich habe Code, der kürzlich von EF 4.2 auf EF 5.0 aktualisiert wurde (eigentlich EF 4.4, da ich auf .Net 4.0 läuft). Ich habe festgestellt, dass ich die Syntax meiner Abfrage ändern musste, und ich bin neugierig, warum. Lassen Sie mich mit dem Problem beginnen.Warum unterstützt EF 5.0 diese EF 4.x LINQ-Syntax nicht beim Kompilieren zu SQL?

Ich habe eine EventLog-Tabelle, die regelmäßig vom Client aufgefüllt wird. Für jedes Ereignisprotokoll wird ein Eintrag in einer Berichtstabelle erstellt. Dies ist die Abfrage, die regelmäßig ausgeführt wird, um Ereignisprotokolle zu ermitteln, die noch keinen Eintrag in der Berichtstabelle enthalten. Die Abfrage, die ich in EF verwenden 4.2 war:

from el in _repository.EventLogs 
where !_repository.Reports.Any(p => p.EventLogID == el.EventlogID) 

Seit dem Upgrade 5.0 ich folgende Fehlermeldung zur Laufzeit erhalten EF:

System.NotSupportedException: Nicht imstande, einen konstanten Wert von Art zu schaffen ‚Namespace .Bericht'. In diesem Kontext werden nur primitive Typen oder Aufzählungstypen unterstützt.

Ich entdeckte, dass das Umschreiben mit der Join-Syntax das Problem behoben. Die folgenden Arbeiten in EF 5.0 und ist in etwa das Äquivalent:

from eventLog in _repository.EventLogs 
join report in _repository.Reports on eventLog.EventlogID equals report.EventLogID into alreadyReported 
where !alreadyReported.Any() 

Einige Leute gemischte Meinungen über das gemischte Syntax/Stil der ersten Abfrage haben kann, aber ich bin wirklich mehr daran interessiert, die, warum dies. Es ist seltsam, dass der EF 4.2-Compiler das SQL für die ursprüngliche Abfrage generieren konnte, das EF 5.0 jedoch ablehnt. Ist das eine Einstellung, die mir fehlt, oder nur eine Verschärfung der Zwänge zwischen den beiden? Warum passiert dies?

+0

Ich persönlich denke, es ist viel besser lesbar als eine Abfrage mit dem verbinden .. –

+1

Könnten Sie dies testen, anstatt 'von el in _repository.EventLogs wo _repository.Reports.All (p => p.EventLogID! = El.EventlogID) '? –

+0

Hey König, ich habe das versucht und habe das gleiche bekommen. Ich habe sogar versucht:! _repository.OntarioReports.Any (p => 5 == 5). Es scheint die gemischte Syntax von dem zu sein, was ich sagen kann. –

Antwort

2

Das Problem wird durch die Art von Ihrem Repository zurückgegeben verursacht wird; Das Problem kann reproduziert werden, wenn _repository.Reports nicht IQueryable<T> ist. In diesem Fall wird die Reports als eine nicht-skalare Variable betrachtet; was übrigens in LINQ nicht erlaubt ist. Siehe Referencing Non-Scalar Variables Not Supported

Auf Ihre Frage, warum die zweite Abfrage funktioniert, ist es im Grunde die folgende Erweiterungsmethode von IQueryable<T> welche Gruppe verbindet es mit IEnumerable<TInner>.

Welche akzeptiert nur den Ausdruck für die Schlüssel-Selektoren für äußere und innere (anstatt nicht skalare Variablen referenzieren); in denen die obige Einschränkung nicht gilt.

Hinweis: Wenn _repository.Reports von IQueryable<T> ist, wird die erste Abfrage funktionieren; weil EF den Ausdrucksbaum korrekt erstellt und das entsprechende SQL ausführt.

0

Just for Kuriositäten willen, haben Sie

versucht Umwandlung
from el in _repository.EventLogs 
where !_repository.Reports.Any(p => p.EventLogID == el.EventlogID) 

zu

from el in _repository.EventLogs 
where !_repository.Reports.Where(p => p.EventLogID == el.EventlogID).Any(); 

oder

from el in _repository.EventLogs 
where !_repository.Reports.Where(p => p.EventLogID == el.EventlogID).Count() > 0; 
+1

sollte das nicht ein Kommentar sein? –

+0

Diese alle produzieren das gleiche Verhalten. –