Betrachten Sie eine Datenbank mit mehreren Tabellen, die zuerst mit Entity Framework-Code erstellt wurden. Jede Tabelle enthält einen anderen Objekttyp, aber ich möchte aus Gründen der Erweiterbarkeit eine einzige generische Abfrage-Builder-Klasse erstellen. Bisher als Rahmen für diese Klasse habe ich eine generische Klasse als so bestimmt als Wrapper für Linq to SQL zu handeln:Wie erstelle ich einen C# Generic Linq Querier?
public class DBQuerier<T>
where T : class
{
DbSet<T> relation;
public DBQuerier(DbSet<T> table)
{
relation = table;
}
public bool Exists(T toCheck);
public void Add(T toAdd);
public T (Get Dictionary<String, Object> fields);
public bool SubmitChanges();
public void Update(T toUpdate, Dictionary<String, Object> fields);
public void Delete(T toDelete);
}
Mein Problem kommt an der ersten Hürde, wenn sie versuchen, um zu prüfen, ob ein Datensatz existiert weil ich nicht zwischen generischem Typ T und einem Objekttyp konvertieren kann, mit dem ich versuche zu arbeiten. Wenn ich Basis Linq:
public bool Exists(T toCheck)
{
return (from row in relation
where row.Equals(toCheck)
select row).Any();
}
Eine Laufzeitausnahme tritt auf, wenn SQL nicht mit alles andere als primitive Typen auch funktionieren kann, wenn ich IComparable
implementieren und meine eigene Equals bezeichnen, die ein einzelnes Feld vergleicht. Lambda-Ausdrücke scheint näher zu kommen, aber dann bekomme ich wieder Probleme mit SQL nicht in der Lage mehr als primitive Typen selbst zu behandeln, obwohl mein Verständnis war, dass Expression.Equal
sie gezwungen, die Klasse vergleichbare Funktion zu verwenden:
public bool Exists(T toCheck)
{
ParameterExpression T1 = Expression.Parameter(typeof(myType), "T1");
ParameterExpression T2 = Expression.Parameter(typeof(myType), "T2");
BinaryExpression compare = Expression.Equal(T1, T2);
Func<T, T, bool> checker =
Expression.Lambda<Func<T, T, bool>>
(compare, new ParameterExpression[] { T1, T2 }).Compile();
return relation.Where(r => checker.Invoke(r, toCheck)).Any();
}
Der Ausdruck tree wurde so entworfen, dass ich später eine switch-Anweisung hinzufügen konnte, um die Abfrage nach dem Typ zu erstellen, den ich mir ansehen wollte. Meine Frage ist: Gibt es einen viel einfacheren/besseren Weg, dies zu tun (oder zu beheben, was ich bisher versucht habe), da die einzigen anderen Optionen, die ich sehen kann, eine Klasse für jede Tabelle zu schreiben sind (nicht so einfach zu erweitern) oder überprüfen Sie jede Seite der Datensatzanwendung (möglicherweise schrecklich langsam, wenn Sie die gesamte Datenbank übertragen müssen)? Entschuldigung, wenn ich so sehr grundlegende Fehler gemacht habe, da ich lange überhaupt nicht mit viel davon gearbeitet habe, danke im Voraus!
Beachten Sie, dass Ihre 'Exists'-Methode nur eine umbenannte' Contains'-Methode ist, ohne dass eine Implementierung so gut ist. – Servy
Wenn Sie eine Primärschlüsselspalte haben, können Sie immer die Methode 'relation.Find (Id)' verwenden, um zu überprüfen, ob sie existiert. – Nilesh