Ich habe die folgende generische Erweiterungsmethode:
public static T GetById<T>(this IQueryable<T> collection, Guid id)
where T : IEntity
{
Expression<Func<T, bool>> predicate = e => e.Id == id;
T entity;
// Allow reporting more descriptive error messages.
try
{
entity = collection.SingleOrDefault(predicate);
}
catch (Exception ex)
{
throw new InvalidOperationException(string.Format(
"There was an error retrieving an {0} with id {1}. {2}",
typeof(T).Name, id, ex.Message), ex);
}
if (entity == null)
{
throw new KeyNotFoundException(string.Format(
"{0} with id {1} was not found.",
typeof(T).Name, id));
}
return entity;
}
Leider weiß Entity Framework nicht, wie es damit umgehen soll, predicate
da C # das Prädikat in Folgendes konvertiert hat:
e => ((IEntity)e).Id == id
Entity Framework löst die folgende Ausnahme aus:
Der Typ 'IEntity' kann nicht in 'SomeEntity' umgewandelt werden. LINQ to Entities unterstützt nur das Umwandeln von EDM-Grund- oder Aufzählungstypen.
Wie können wir Entity Framework mit unserer IEntity
Schnittstelle zum Laufen bringen?
Einige zusätzliche Erklärungen zum
class
"Fix".Diese Antwort zeigt zwei verschiedene Ausdrücke, einen mit und einen ohne
where T: class
Einschränkung. Ohne dieclass
Einschränkung haben wir:und mit der Einschränkung:
Diese beiden Ausdrücke werden vom Entity-Framework unterschiedlich behandelt. Wenn man sich die EF 6-Quellen ansieht , kann man feststellen, dass die Ausnahme von hier kommt, siehe
ValidateAndAdjustCastTypes()
.Was passiert ist, dass EF versucht,
IEntity
in etwas zu verwandeln, das für die Domain-Modellwelt sinnvoll ist, dies jedoch fehlschlägt, weshalb die Ausnahme ausgelöst wird.Der Ausdruck mit der
class
Einschränkung enthält nicht denConvert()
Operator, die Umwandlung wird nicht versucht und alles ist in Ordnung.Es bleibt die Frage offen, warum LINQ unterschiedliche Ausdrücke erstellt. Ich hoffe, dass ein C # -Werker dies erklären kann.
quelle
Entity Framework unterstützt dies nicht sofort, aber ein
ExpressionVisitor
Ausdruck, der den Ausdruck übersetzt, ist einfach zu schreiben:Das einzige, was Sie tun müssen, ist, das übergebene Prädikat mit dem Ausdruck Besucher wie folgt zu konvertieren:
Ein anderer flexibler Ansatz besteht darin, Folgendes zu nutzen
DbSet<T>.Find
:quelle
Ich hatte den gleichen Fehler, aber ein ähnliches, aber unterschiedliches Problem. Ich habe versucht, eine Erweiterungsfunktion zu erstellen, die IQueryable zurückgibt, aber die Filterkriterien basieren auf der Basisklasse.
Ich fand schließlich die Lösung für meine Erweiterungsmethode .Select (e => e als T), wobei T die untergeordnete Klasse und e die Basisklasse ist.
Ausführliche Informationen finden Sie hier: Erstellen Sie die IQueryable <T> -Erweiterung mithilfe der Basisklasse in EF
quelle