web-dev-qa-db-de.com

Verwendung von Prädikaten in LINQ to Entities für Entity Framework-Objekte

Ich verwende LINQ to Entities für Entity Framework-Objekte in meiner Datenzugriffsebene.

Mein Ziel ist es, so viel wie möglich aus der Datenbank zu filtern, ohne Filterlogik auf speicherinterne Ergebnisse anzuwenden.

Zu diesem Zweck übergibt Business Logic Layer ein Prädikat an Data Access Layer.

Ich meine

Func<MyEntity, bool>

Also, wenn ich dieses Prädikat direkt benutze, wie

public IQueryable<MyEntity> GetAllMatchedEntities(Func<MyEntity, Boolean> isMatched)
{
    return qry = _Context.MyEntities.Where(x => isMatched(x));
}

Ich bekomme die Ausnahme

[System.NotSupportedException] --- {"Der LINQ-Ausdrucksknotentyp 'Invoke' wird in LINQ to Entities nicht unterstützt."}

Lösung in diese Frage schlägt vor, AsExpandable () Methode von zu verwenden LINQKit Bibliothek.

Aber wieder mit

public IQueryable<MyEntity> GetAllMatchedEntities(Func<MyEntity, Boolean> isMatched)
{
    return qry = _Context.MyEntities.AsExpandable().Where(x => isMatched(x));
}

Ich bekomme die Ausnahme

Objekt vom Typ 'System.Linq.Expressions.FieldExpression' kann nicht in 'System.Linq.Expressions.LambdaExpression' umgewandelt werden

Gibt es eine Möglichkeit, ein Prädikat in der LINQ to Entities-Abfrage für Entity Framework-Objekte zu verwenden, damit es korrekt in eine SQL-Anweisung umgewandelt wird?.

Vielen Dank.

22
bairog

Sie benötigen dazu kein LinqKit. Denken Sie daran, zu verwenden

Expression<Func<MyEntity, bool>>

anstatt von

Func<MyEntity, bool>

Etwas wie das:

public IQueryable<MyEntity> GetAllMatchedEntities(Expression<Func<MyEntity, Boolean>> predicate)
{
    return _Context.MyEntities.Where(predicate);
}

Sie müssen Expression verwenden, da Linq to Entities Ihr Lambda in SQL übersetzen muss.

Wenn Sie Func verwenden, wird Ihr Lambda in IL kompiliert, aber wenn Sie Expression verwenden, ist es ein Ausdrucksbaum, den Linq in Entities transversieren und konvertieren kann.

Dies funktioniert mit Ausdrücken, die von Linq to Entities verstanden werden.

Wenn dies weiterhin fehlschlägt, führt Ihr Ausdruck eine Aktion aus, die von Linq to Entities nicht in SQL übersetzt werden kann. In diesem Fall glaube ich nicht, dass LinqKit helfen wird.

Bearbeiten:

Es ist keine Konvertierung erforderlich. Definieren Sie einfach die Methode GetAllMatchedEntities mit einem Expression-Parameter und verwenden Sie sie genauso wie mit einem Func-Parameter. Den Rest erledigt der Compiler.

Es gibt drei Möglichkeiten, wie Sie GetAllMatchedEntities verwenden können.

1) Mit einem Inline-Lambda-Ausdruck:

this.GetAllMatchedEntities(x => x.Age > 18)

2) Definieren Sie Ihren Ausdruck als Feld (kann auch eine Variable sein)

private readonly Expression<Func<MyEntity, bool>> IsMatch = x => x.Age > 18;
...then use it
this.GetAllMatchedEntities(IsMatch)

3) Sie können Ihren Ausdruck manuell erstellen. Die Verkleinerung ist mehr Code und Sie verpassen die Kompilierungszeitprüfungen.

public Expression<Func<MyEntity, bool>>  IsMatchedExpression()
{
    var parameterExpression = Expression.Parameter(typeof (MyEntity));
    var propertyOrField = Expression.PropertyOrField(parameterExpression, "Age");
    var binaryExpression = Expression.GreaterThan(propertyOrField, Expression.Constant(18));
    return Expression.Lambda<Func<MyEntity, bool>>(binaryExpression, parameterExpression);
}
44
andres.chort

In Linq to Entities verwendete Methoden müssen vom Linq-Anbieter kanonisch zugeordnet werden, damit sie funktionieren. Da der Linq-Anbieter, in Ihrem Fall EF, Ihr Prädikat keiner internen Methode zuordnen konnte, wurde ein Fehler ausgegeben.

In LINQ-Szenarien umfassen Abfragen zum Entity Framework das Zuordnen bestimmter CLR-Methoden zu Methoden in der zugrunde liegenden Datenquelle über kanonische Funktionen. Alle Methodenaufrufe in einer LINQ to Entities-Abfrage, die nicht explizit einer kanonischen Funktion zugeordnet sind, führen dazu, dass eine NotSupportedException-Laufzeitausnahme ausgelöst wird

Quelle: CLR-Methode für Canonical Function Mapping ( http://msdn.Microsoft.com/en-us/library/bb738681.aspx )

Sie können versuchen, die Methoden, die [~ # ~] zugeordnet sind , zu verwenden und in Ihren Linq-Ausdruck zu verketten, oder eine gespeicherte Methode verwenden Verfahren. Aber bis EF die gesamte CLR unterstützt, müssen Sie eine Umgehungslösung finden.

Auf der positiven Seite scheint jede Veröffentlichung der kanonischen Liste ein bisschen mehr hinzuzufügen.

Lesen Sie als mögliche Abhilfe: http://msdn.Microsoft.com/en-us/library/dd456857.aspx

3
Gayot Fow