Frage

Gibt es eine Möglichkeit, die CompiledQuery.Compile Methode zu verwenden, um die Expression mit einem IQueryable assoziiert zu kompilieren? Zur Zeit habe ich eine IQueryable mit einem sehr großen Ausdruck Baum dahinter. Die IQueryable wurde unter Verwendung von mehreren Verfahren jeder Versorgungskomponenten, die aufgebaut. Zum Beispiel können zwei Methoden IQueryables zurück, die dann in einem dritten verbunden. Aus diesem Grunde kann ich nicht explizit den gesamten Ausdruck in der Kompilierung () -Methode definieren.

Ich habe gehofft, den Ausdruck passieren, um die Kompilierung Methode als someIQueryable.Expression aber dieser Ausdruck ist in der Form nicht von der Kompilierung Methode erforderlich. Wenn ich versuche, und dieses Problem zu umgehen, indem Sie die Abfrage direkt in die Kompilierung Methode setzen, zum Beispiel:

    var foo = CompiledQuery.Compile<DataContext, IQueryable<User>>(dc => dc.getUsers());
    var bar = foo(this);

, wo ich den Anruf Form innerhalb eines Datacontext machen, erhalte ich eine Fehlermeldung, dass „GetUsers nicht als gespeicherte Prozedur oder benutzerdefinierte Funktion abgebildet wird“. Ich kann wieder nicht nur den Inhalt der GetUsers Methode kopieren, wo ich die Kompilierung Anruf, da sie wiederum die Verwendung anderer Methoden macht.

Gibt es eine Möglichkeit, die Expression auf der IQueryable von „GetUsers“ in die Methode Compile zurückgegeben passieren?

Aktualisiert Ich habe versucht, meinen Willen auf dem System mit dem folgenden Code zu erzwingen:

    var phony = Expression.Lambda<Func<DataContext, IQueryable<User>>>(
        getUsers().Expression, Expression.Parameter(typeof(DataContext), "dc"));

    Func<DataContext, IQueryable<User>> wishful = CompiledQuery.Compile<DataContext, IQueryable<User>>(phony);
    var foo = wishful(this);

foo endet als:

{System.Data.Linq.SqlClient.SqlProvider + OneTimeEnumerable`1 [Model.Entities.User]}

Ich habe nicht die Möglichkeit, die Ergebnisse in foo, um zu sehen, wie statt und bietet die Ergebnisse zu erweitern und die Abfrage ausführt Ich sehe nur die Meldung „Operation konnte die Laufzeit destabilisieren“.

Ich muss nur einen Weg für die SQL-Zeichenfolge finden nur einmal und als paramaterized Befehl auf nachfolgende Anfragen verwendet erzeugt werden, kann ich dies tun manuell die GetCommand Methode auf dem Datenkontext verwenden, aber dann muss ich explizit festgelegt alle Parameter und tun mir das Objekt abbildet, die ein paar hundert Zeilen Code ist die Komplexität dieser speziellen Abfrage angegeben.

Aktualisiert

John Rusk die nützlichsten Informationen, so dass ich ihm den Sieg auf diesem ausgezeichnet. Allerdings wurde einige zusätzliche Optimierungen erforderlich, und es gab ein paar andere Fragen, die ich auf dem Weg begegnet, so dachte ich, ich würde ‚erweitern‘ auf die Antwort. Zum einen das ‚könnte Betrieb destabalize der Laufzeit‘ Fehler in der Zusammenstellung des Ausdrucks nicht fällig war, war es eigentlich wegen einiger Gießen tief im Ausdrucksbaum. An einigen Stellen musste ich die .Cast<T>() Methode aufzurufen, um formell Artikel zu werfen, auch wenn sie den richtigen Typ waren. Ohne zu sehr ins Detail dies war im Grunde erforderlich, wenn mehrere Ausdruck in einen einzigen Baum zusammengefasst wurde und jeder Zweig könnte eine andere Art zurückgeben, die jeweils den Untertyp einer gemeinsamen Klasse waren.

Nach dem destabalizing Problem zu lösen, kehrte ich in die Zusammenstellung Problem. Johns erweitern Lösung war fast da. Es sah für Methodenaufruf Ausdrücke im Baum und versuchte, sich zu dem zugrunde liegenden Ausdruck zu lösen, dass Verfahren in der Regel zurückkehren würden. Meine Verweise auf Ausdrücke wurden nicht durch Methodenaufrufe zur Verfügung gestellt, sondern Eigenschaften. Also brauchte ich den Ausdruck Besucher zu ändern, die die Expansion führt diese Typen sind:

protected override Expression VisitMemberAccess(MemberExpression m) {
    if(m.Method.DeclaringType == typeof(ExpressionExtensions)) {
        return new ExpressionExpander().Visit((Expression)(((System.Reflection.PropertyInfo)m.Member).GetValue(null, null)));
    }
    return base.VisitMemberAccess(m);
}

Dieses Verfahren kann in allen Fällen nicht angemessen sein, aber es sollte jemand helfen, die sich in der gleichen Situation befindet.

War es hilfreich?

Lösung

So etwas wie dies funktioniert, zumindest in meinen Tests:

Expression<Func<DataContext, IQueryable<User>> queryableExpression = GetUsers();
var expressionWithSomeAddedStuff = (DataContext dc) => from u in queryableExpression.Invoke(dc) where ....;
var expressionThatCanBeCompiled = expressionWithSomeAddedStuff.Expand();
var foo = CompiledQuery.Compile<DataContext, IQueryable<User>>(expressionThatCanBeCompiled);

Das sieht ein bisschen ausführlicher, und es gibt wahrscheinlich Verbesserungen, die Sie machen können.

Sie entscheidende Punkt ist, dass es die Invoke und erweitern Methoden von LinqKit verwendet. Sie im Grunde können Sie eine Abfrage aufzubauen, durch Zusammensetzung und dann das fertige Ergebnis kompilieren.

Lizenziert unter: CC-BY-SA mit Zuschreibung
Nicht verbunden mit StackOverflow
scroll top