Ich bin auf ein sehr seltsames LINQ to SQL Verhalten / Bug gestoßen, das ich einfach nicht verstehen kann.
Nehmen wir als Beispiel die folgenden Tabellen: Kunden - & gt; Bestellungen - & gt; Details.
Jede Tabelle ist eine Untertabelle der vorherigen Tabelle mit einer regulären Primär-Fremdschlüssel-Beziehung (1 zu vielen).
Wenn ich die folgende Abfrage ausführe:
%Vor%Dann bekomme ich eine Ausnahme: Konnte den Knoten 'Value' nicht zur Ausführung als SQL formatieren.
Aber die folgenden Abfragen werfen keine Ausnahme:
%Vor%Wenn ich meine primäre Abfrage wie folgt ändere, bekomme ich keine Ausnahme:
%Vor% Jetzt konnte ich verstehen, dass die letzte Abfrage aufgrund der folgenden Logik funktioniert:
Da es keine Zuordnung von "new Order ()" zu SQL gibt (ich vermute hier), muss ich stattdessen an einer lokalen Liste arbeiten.
Aber was ich nicht verstehen kann, warum funktionieren die anderen beiden Abfragen?!?
Ich könnte möglicherweise die Arbeit mit der "lokalen" Version von context.Customers.ToList () akzeptieren, aber wie kann ich die Abfrage beschleunigen?
Zum Beispiel bin ich im letzten Abfrage-Beispiel ziemlich sicher, dass jede Auswahl eine neue SQL-Abfrage ausführen wird, um die Bestellungen abzurufen. Jetzt konnte ich das faule Laden vermeiden, indem ich DataLoadOptions benutze, aber dann würde ich tausende von Order-Zeilen ohne Grund abrufen (ich brauche nur die erste Zeile) ...
Wenn ich die gesamte Abfrage in einer SQL-Anweisung so ausführen könnte, wie ich möchte (mein erstes Abfrage-Beispiel), dann wäre die SQL-Engine selbst intelligent genug, um nur eine Bestellzeile für jeden Kunden abzurufen ...
Gibt es vielleicht eine Möglichkeit, meine ursprüngliche Abfrage so zu schreiben, dass sie wie vorgesehen funktioniert und auf einen Schlag vom SQL-Server ausgeführt wird?
BEARBEITEN:
(längere Antwort für Arturo)
Die Abfragen, die ich zur Verfügung gestellt habe, sind rein zu Beispielzwecken. Ich weiß, dass sie alleine sinnlos sind, ich wollte nur ein simples Beispiel zeigen.
Der Grund, warum Ihr Beispiel funktioniert, ist, dass Sie es vermieden haben, "new Order ()" alle zusammen zu verwenden. Wenn ich Ihre Abfrage leicht modifiziere, um sie weiterhin zu verwenden, bekomme ich immer noch eine Ausnahme:
%Vor% Obwohl diesmal die Ausnahme etwas anders ist - Konnte Knoten 'ClientQuery' nicht für die Ausführung als SQL formatieren.
Wenn ich die ?? -Syntax anstelle von (x? Y: z) in dieser Abfrage verwende, bekomme ich dieselbe Ausnahme wie ursprünglich.
In meiner Real-Life-Abfrage brauche ich nicht Count () , ich muss einige Eigenschaften aus der letzten Tabelle auswählen (was in meinen vorherigen Beispielen Details wäre). Im Wesentlichen muss ich Werte aller Reihen in jeder Tabelle zusammenführen. Um ein dickeres Beispiel zu geben, muss ich zuerst meine Tabellen neu formulieren:
Modelle - & gt; ModelCategoryVariations & lt; - Kategorievariationen - & gt; CategoryVariationItems - & gt; ModelModuleCategoryVariationItemAmounts - & gt; ModelModuleCategoryVariationItemAmountValueChanges
Das - & gt; Zeichen steht für ein 1 - & gt; viele Beziehungen. Beachten Sie, dass es ein Zeichen gibt, das umgekehrt ist ...
Meine echte Abfrage würde etwa so aussehen:
%Vor% Diese Abfrage explodiert in der Zeile let mmcvia = .
Wenn ich mich richtig erinnere, würde die Abfrage mit let mmcvia = new ModelModuleCategoryVariationItemAmount () beim nächsten ?? -Operanden explodieren, was bei Amount =
Wenn ich die Abfrage mit aus m in context.Models.ToList () starte, funktioniert alles ...
Warum untersuchen Sie nur die individuelle Zählung, ohne etwas in Bezug auf den Kunden auszuwählen?
Sie können Folgendes tun:
%Vor%BEARBEITEN:
OK, ich denke, Sie haben Ihre Anfrage noch komplizierter gemacht.
Das Problem ist, dass Sie die new WhateverObject()
in Ihrer Abfrage verwenden, T-SQL weiß nichts darüber; T-SQL kennt Datensätze auf Ihrer Festplatte, Sie werfen etwas, das nicht existiert. Nur C # weiß davon. NUTZEN SIE new
NICHT IN IHREN ANDEREN AUSSAGEN, ALS IN DER ÄUSSERSTEN AUSWAHL AUSWÄHLEN, da dies C # empfängt und C # neue Instanzen von Objekten erstellt.
Natürlich wird es funktionieren, wenn Sie die ToList () -Methode verwenden, aber die Leistung ist davon betroffen, weil Sie jetzt Ihren Anwendungs-Host und SQL-Server zusammenarbeiten, um Ihnen die Ergebnisse zu liefern, und es möglicherweise viele Aufrufe an Ihre Datenbank benötigt .
Versuchen Sie es stattdessen:
%Vor%Mit der Select () -Methode können Sie den ersten Betrag oder seinen Standardwert abrufen. Ich habe nur "0" als Beispiel verwendet, ich weiß nicht, was Ihr Standardwert für Betrag ist.
Tags und Links linq-to-sql