Erstellen eines benutzerdefinierten Prädikats, das mithilfe einer foreach-Schleife als Filter fungiert

c# expression-trees linq-expressions linqkit linq-to-entities

Frage

Ich muss eine Liste von Dokumenten filtern, indem ich sie an einen benutzerdefinierten Filter übergebe, den ich mit einer foreach Schleife dynamisch erstellen foreach :

var mainPredicate = PredicateBuilder.True<Document>();

// mainPredicate is combined to other filters successfully here ...

var innerPredicate = PredicateBuilder.False<Document>();
foreach (var period in periods)
{
    var p = period;
    Expression<Func<Document, bool>> inPeriod =
        d => d.Date >= p.DateFrom && d.Date <= p.DateTo;

    innerPredicate = innerPredicate.Or(d => inPeriod.Invoke(d));
}

mainPredicate = mainPredicate.And(innerPredicate);

Diese letzte Zeile:

documents = this.ObjectSet.AsExpandable().Where(mainPredicate).ToList();

Löst diese Ausnahme aus:

Der Parameter 'd' wurde im angegebenen LINQ to Entities-Abfrageausdruck nicht gebunden.

Wer weiß, warum ich diese Ausnahme bekomme? Ich verstehe nicht, wo der 'd' Parameter, den ich an die InPeriod-Methode übergebe, verloren geht. Ich weiß nicht, was dafür fehlt. Mein Code ist der gleiche wie viele andere Beispiele, die perfekt funktionieren. Jede zusätzliche theorisch-theoretische Information über das Aufrufen von Ausdrücken und wie es hinter den Kulissen funktioniert, ist willkommen.

Akzeptierte Antwort

Schließlich habe ich einen Weg gefunden, die Kombination mehrerer Prädikate mit dem Haupt-Ausdrucksbaum zu vermeiden.

Da jedes Prädikat einen anderen Filter darstellt , und ich möchte , dass die endgültige, kombinierte Filter eine Reihe von Pflicht werden angesehener Bedingungen sein, können wir sagen , dass jeder der Prädikate wahr zurückgeben muss für das letzte Prädikat true zurück.

Damit das funktioniert, müssen die Prädikate mit AND kombiniert werden. Die resultierende SQL-Abfrage muss also so aussehen:

predicate1 AND predicate2 AND predicate3 ...

Eine bessere Möglichkeit , diese Prädikate zu kombinieren AND zu Kette Where Abfrageoperatoren auf die letzte Abfrage, wie folgt aus :

var documents = this.ObjectSet.AsExpandable()
    .Where(mainPredicate)
    .Where(otherPredicate)
    .Where(yetAnotherPredicate)
    .ToList();

Die resultierende SQL-Abfrage wird jedes dieser Prädikate mit AND kombinieren. Genau das wollte ich tun.

Es ist einfacher, als einen eigenen Expressionbaum zu hacken.


Beliebte Antwort

Ich verstehe nicht, warum du das tust:

innerPredicate = innerPredicate.Or(d => inPeriod.Invoke(d));

Wenn Sie das Invoke vollständig vermeiden könnten, wie Invoke :

innerPredicate = innerPredicate.Or(inPeriod);

Das sollte perfekt funktionieren.


BTW, ich habe das Gefühl, dass es hier einen Fehler mit LINQKit gibt (es sei denn, es gibt einige Dokumente, die darauf hindeuten, dass dieses Szenario nicht unterstützt wird).

Als ich diesen ähnlichen Code ausprobiert habe:

 Expression<Func<int, bool>> first = p1 => p1 > 4;
 Expression<Func<int, bool>> second = p2 => p2 < 2;

// Expand is similar to AsExpandable, except it works on 
// expressions, not queryables.
var composite = first.Or(d => second.Invoke(d))
                     .Expand();

... LINQKit hat den folgenden zusammengesetzten Ausdruck generiert:

p1 => ((p1 > 4) OrElse (d < 2)) // what on earth is d?

... welches tatsächlich den ungebundenen Parameter d hat (NodeType = Parameter, Name = 'd').

Ausweichen der Invoke mit first.Or(second).Expand() erzeugt das vollkommen Sinnvolle:

p1 => ((p1 > 4) OrElse (p1 < 2)) // much better now...


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