Warum entfernt Linq-to-sql fälschlicherweise Felder in meiner Vereinigung?

9

Ich versuche, mehrere Abfragen zu aggregieren, um eine aktuelle Aktualisierungsanzeige für meine Benutzer bereitzustellen, die eine gemeinsame Datenstruktur für die Union-Unterstützung verwenden. In meiner ersten Funktion habe ich die folgende Auswahlklausel:

%Vor%

Wenn dies aufgerufen wird, wird eine Abfrage generiert, die 9 Felder zurückgibt. Die zweite Methode ist:

%Vor%

Wenn diese Abfrage selbst ausgeführt wird, gibt sie 9 Werte korrekt zurück. Wenn ich es jedoch versuche,

%Vor%

Ich bekomme eine sql-Ausnahme, dass die Abfrage fehlgeschlagen ist, weil nicht alle Abfragen die gleiche Anzahl von Feldern haben. Die Untersuchung des generierten SQL zeigt, dass die erste Abfrage korrekt ist, aber Linq generiert die zweite (unioned) Abfrage, um nur 7 Felder zu haben. Nach dem Testen scheint es, dass Linq die Nullen zu "optimieren" scheint, so dass es nur eine Null-Spalte anstelle von 3 zurückgibt, was zu einer falschen Übereinstimmung führt.

Warum erzeugt Linq-to-sql fälschlicherweise die Union und wie kann ich das umgehen?

Bearbeiten:

Ok, das Problem scheint sich mit der Verkettung von Verbindungen in Linq-zu-Sql für .Net 3.5 zu befassen. Dies passiert anscheinend nicht in 4. Mit dem folgenden Code:

%Vor%

I dann Unionskette via: var q2 = Test1().Union(Test2()).Union(Test1());

In .Net 3.5 bekomme ich die folgende sql, die eine falsche Übereinstimmung hat und fehlschlägt

%Vor%

In .net 4 wird folgender Code erzeugt:

%Vor%

Das ist gültig sql und funktioniert. Da wir aus verschiedenen Gründen unsere Produktionssysteme nicht auf .net 4 bringen können, weiß jemand einen Weg, wie ich das in .net 3.5 umgehen kann?

    
KallDrexx 25.06.2012, 22:05
quelle

2 Antworten

3

Dies ist eine aktualisierte Antwort - es scheint, dass in 3.5 die Optimierung nicht ausgeschaltet werden kann. Ich habe viele Dinge in LinqPad ausprobiert, und sobald es einen C # -Ausdruck gibt, der nicht von einer Spalte abgeleitet ist, entfernt der Abfragecompiler ihn aus dem SQL.

Wir brauchen also etwas, das aus einem Spaltenausdruck abgeleitet wird, aber wir können immer zwingen, null zu sein.

Hier ist eine Lösung, mit der ich arbeiten konnte: Schreiben Sie einen bedingten Ausdruck, der null zurückgibt, wenn ein Spaltenwert gleich ist; also immer null zurückgeben. Es wird nicht schön sein, denn Linq to Sql in 3.5 scheint bei der Optimierung einer Abfrage aggressiv sehr zu sein (wir müssen für jeden null , den wir wollen, eindeutige Vergleiche verwenden, zB == in verwenden eins, dann != auf dem nächsten und so weiter); und es wird hässlicher, wenn wir es modifizieren, um mit Nullen fertig zu werden, wenn Sie diesen Hack auf einer Spalte ausführen müssen, die NULL-fähig ist:

Ich wähle nur Spaltennamen aus, die ich in Ihrem Code sehen kann - aber Sie möchten vielleicht andere verwenden:

%Vor%

In LinqPad erhalte ich für jede Anweisung, in der ich ? : verwende, einen Spaltenausdruck im generierten SQL. Die "" auf der anderen Seite des Ausdrucks ist, weil SQL über CASE -Anweisungen mit mehr als einer NULL stöhnt.

Ganz klar - diese Lösung ist nicht nur hässlich, sondern auch abhängig davon, wie viele Spalten für diese gefälschten Vergleiche zur Verfügung stehen und wie viele eindeutige Vergleiche tatsächlich von L2S abgebildet werden.

    
Andras Zoltan 25.06.2012, 22:44
quelle
0
  1. Team, UpdateComments, State sind null oder null. Sie sollten also für beide Fälle denselben Wert angeben.
  2. Wenn Sie den Standardvergleich verwenden, ist UpdateMessage anders, also unterscheiden sich die Objekte. So können Sie statt Union concat.
gandil 25.06.2012 22:55
quelle

Tags und Links