Kompiliertes LINQ-zu-SQL-Abfrageproblem (funktioniert als nicht kompilierte Abfrage)

c# compiled-query expression-trees linq linq-to-sql

Frage

Ich habe C # -Erweiterungsmethoden auf IQueryable , zB FindNewCustomers() und FindCustomersRegisteredAfter(int year) und so weiter, die ich verwende, um eine Abfrage für LINQ to SQL zusammen zu " FindCustomersRegisteredAfter(int year) ".

Nun zu meinem Problem: Ich möchte kompilierte Abfragen erstellen, zB:

 private static Func<MyDataContext, SearchInfo, IQueryable<Customer>>
        CQFindAll = 
            CompiledQuery.Compile((MyDataContext dc, SearchInfo info) =>
                dc.Contacts.Select(c => c).FindCustomersRegisteredAfter(info.RegYear)
                           .OrderBy(info.OrderInfo)
                           .Skip(info.SkipCount)
                           .Take(info.PageSize));

Die Methode FindCustomersRegisteredAfter(int year) ist eine Erweiterungsmethode, die ein IQueryable und dasselbe IQueryable . Die OrderBy Methode ist ebenfalls eine Erweiterungsmethode (System.Linq.Dynamic), die einen dynamischen Ausdruck basierend auf einem String erstellt (zB "FirstName ASC" wird das Feld FirstName aufsteigend sortieren). Skip und Take sind die eingebauten Methoden.

Das obige (nicht als kompilierte Abfrage, sondern regelmäßige Abfrage) funktioniert perfekt . Sobald ich es in eine kompilierte Abfrage einfüge, treffe ich den folgenden Fehler:

Methode 'System.Linq.IQueryable`1 [Domäne.Kunden] FindCustomersRegisteredAfter [Customer] (System.Linq.IQueryable`1 [Domäne.Kunden], Int32)' hat keine unterstützte Übersetzung in SQL.

Auch dies funktioniert einwandfrei, wenn die Abfrage nicht kompiliert ist , sondern nur eine normale LINQ-Abfrage. Der Fehler wird nur angezeigt, wenn er sich in CompiledQuery.Compile () befindet.

Hilfe??!

Edit: Wenn ich die Abfrage über var query = (...) auf die gleiche Weise wie in CompiledQuery.Compile erzeuge, ist dies das generierte SQL:

 private static Func<MyDataContext, SearchInfo, IQueryable<Customer>>
        CQFindAll = 
            CompiledQuery.Compile((MyDataContext dc, SearchInfo info) =>
                dc.Contacts.Select(c => c).FindCustomersRegisteredAfter(info.RegYear)
                           .OrderBy(info.OrderInfo)
                           .Skip(info.SkipCount)
                           .Take(info.PageSize));

Sie sehen also, dass das SQL perfekt übersetzbar ist, so dass ich nur @ p0, @ p1 und @ p2 ausfüllen muss, damit dies wiederholt funktioniert! Was ist falsch mit CompiledQuery.Compile?!?

Update: Ich verstehe, dass OrderBy nicht funktionieren kann (da es kein @ p-Parameter ist). Ich versuche immer noch herauszufinden, warum CompiledQuery.Compile nicht mit meinen Erweiterungsmethoden funktioniert. Informationen im Internet zu diesem Thema gibt es praktisch nicht.

Akzeptierte Antwort

Ich glaube, die kompilierte Abfrage muss in SQL übersetzt werden können, was Ihre Erweiterungsmethode nicht sein kann. Wenn Sie das von Ihrer "normalen" Abfrage erstellte SQL profilieren, stellen Sie möglicherweise fest, dass es die gesamte Tabelle auswählt, damit es alle Zeilen in Ihre Erweiterungsmethode einspeisen kann.

Sie sollten Ihre Filterlogik besser in die Abfrage einfügen (als Teil der Ausdrucksbaumstruktur), damit sie in SQL übersetzt und serverseitig ausgeführt werden kann.

Der OrderBy ist auch ein Problem wegen des Skip. Sie müssen dies übersetzbar in SQL oder LINQ müssen alle Zeilen zurückgeben, um sie clientseitig zu filtern.

Wenn Sie diese nicht als LINQ-Ausdrücke ausdrücken können, sollten Sie in Betracht ziehen, SQL-Funktionen auf dem Server zu erstellen und sie Ihrem DataContext zuzuordnen. LINQ kann diese in die T-SQL-Funktionsaufrufe übersetzen.

BEARBEITEN:

Ich nehme an, ich nahm an, dass Ihre Erweiterungsmethoden keine Ausdrucksbäume erstellen. Es tut uns leid.

Betrachten Sie diesen Link, der Ihrem Problem ähnelt. Es verweist auf einen anderen Link , der ausführlicher ist.

Es sieht so aus, als ob der MethodCallExpression das Problem ist.

Der Code ist ein bisschen lang, um hier gepostet zu werden, aber ähnlich wie der Expander von tomasp.net, besuche ich jeden Ausdruck im Ausdrucksbaum und wenn der Knoten eine MethodCallExpression ist, die eine Methode aufruft, die einen Ausdrucksbaum zurückgibt, ersetze ich diesen MethodCallExpression durch den Ausdrucksbaum, der durch Aufrufen der Methode zurückgegeben wird.

Das Problem besteht also darin, dass die Methode beim Kompilieren der Abfrage nicht ausgeführt wird, sodass keine Ausdrucksbaumstruktur in SQL übersetzt werden muss.




Lizenziert unter: CC-BY-SA with attribution
Nicht verbunden mit Stack Overflow
Ist diese KB legal? Ja, lerne warum
Lizenziert unter: CC-BY-SA with attribution
Nicht verbunden mit Stack Overflow
Ist diese KB legal? Ja, lerne warum