Ich musste nur ein ORM auswechseln und es war eine relativ entmutigende Aufgabe, da die Abfragelogik überall leckte. Wenn ich jemals eine neue Anwendung entwickeln müsste, wäre es meine persönliche Präferenz, die gesamte Abfragelogik (unter Verwendung eines ORM) zu kapseln, um sie zukunftssicher für Änderungen zu machen. Das Repository-Muster ist recht schwierig zu codieren und zu pflegen. Daher habe ich mich gefragt, ob es noch andere Muster gibt, mit denen das Problem behoben werden kann.
Ich kann Beiträge vorhersehen, in denen es darum geht, keine zusätzliche Komplexität hinzuzufügen, bevor es tatsächlich benötigt wird, agil zu sein usw. Aber ich bin nur daran interessiert, wie vorhandene Muster ein ähnliches Problem auf einfachere Weise lösen.
Mein erster Gedanke war, ein generisches Typrepository zu haben, zu dem ich über Erweiterungsmethoden nach Bedarf Methoden zu bestimmten Typrepository-Klassen hinzufüge, aber das Testen statischer Methoden durch Einheiten ist furchtbar schmerzhaft. IE:
public static class PersonExtensions
{
public static IEnumerable<Person> GetRetiredPeople(this IRepository<Person> personRep)
{
// logic
}
}
quelle
Antworten:
Zuallererst: Ein generisches Repository sollte als Basisklasse und nicht als vollständige Implementierung betrachtet werden. Es sollte Ihnen helfen, die gängigen CRUD-Methoden zu implementieren. Sie müssen jedoch noch die Abfragemethoden implementieren:
Zweite:
Kehre nicht zurück
IQueryable
. Es ist eine undichte Abstraktion. Versuchen Sie, diese Schnittstelle selbst zu implementieren, oder verwenden Sie sie ohne Kenntnis des zugrunde liegenden Datenbankanbieters. Zum Beispiel hat jeder DB-Provider eine eigene API zum eifrigen Laden von Entitäten. Deshalb ist es eine undichte Abstraktion.Alternative
Alternativ können Sie Abfragen verwenden (z. B. wie durch das Trennmuster Befehl / Abfrage definiert). CQS ist in Wikipedia beschrieben.
Sie erstellen grundsätzlich Abfrageklassen, die Sie aufrufen:
Das Tolle an Abfragen ist, dass Sie verschiedene Datenzugriffsmethoden für verschiedene Abfragen verwenden können, ohne den Code zu überladen. Sie können beispielsweise einen Webdienst in einem, einen anderen in einem anderen und ADO.NET in einem dritten verwenden.
Wenn Sie an einer .NET-Implementierung interessiert sind, lesen Sie meinen Artikel: http://blog.gauffin.org/2012/10/griffin-decoupled-the-queries/
quelle
YourProject.YourDomainModelName.Queries
diesen einfügen, ist die Navigation einfach.Zuerst denke ich, dass ORM schon groß genug ist, um über Ihre Datenbank zu abstrahieren. Einige ORMs bieten Bindungen für alle gängigen relationalen Datenbanken (NHibernate verfügt über Bindungen für MSSQL, Oracle, MySQL, Postgress usw.). Daher erscheint es mir nicht rentabel, eine neue Abstraktion darüber aufzubauen. Außerdem ist die Argumentation, dass Sie dieses ORM "abstrahieren" müssen, bedeutungslos.
Wenn Sie diese Abstraktion dennoch erstellen möchten, würde ich gegen das Repository-Muster verstoßen. Es war großartig im Zeitalter von reinem SQL, aber es ist im Hinblick auf modernes ORM ziemlich mühsam. Dies liegt hauptsächlich daran, dass Sie die meisten ORM-Funktionen wie CRUD-Operationen und Abfragen erneut implementieren.
Wenn ich solche Abstraktionen bauen würde, würde ich diese Regeln / Muster verwenden
In der konkreten Implementierung würde ich CRUD-Operationen von ORM direkt verwenden, ohne einen Wrapping. Ich würde auch einfache Abfragen direkt im Code machen. Komplexe Abfragen würden jedoch in eigenen Objekten gekapselt. Um den ORM "auszublenden", würde ich versuchen, den Datenkontext transparent in ein Dienst- / UI-Objekt einzufügen und das gleiche tun, um Objekte abzufragen.
Das Letzte, was ich sagen möchte, ist, dass viele Leute ORM benutzen, ohne zu wissen, wie man es benutzt und wie man den besten "Profit" daraus macht. Die Leute, die Repositories empfehlen, sind normalerweise von dieser Art.
Als empfohlene Lektüre würde ich Ayendes Blog nennen , insbesondere diesen Artikel .
quelle
Das Problem mit der undichten Implementierung besteht darin, dass Sie viele verschiedene Filterbedingungen benötigen.
Sie können diese API eingrenzen, wenn Sie eine Repository-Methode FindByExample implementieren und sie folgendermaßen verwenden
quelle
Erwägen Sie, Ihre Erweiterungen auf IQueryable anstatt auf IRepository laufen zu lassen.
Zum Komponententest:
Zum Testen ist keine Verspottung erforderlich. Sie können diese Erweiterungsmethoden auch kombinieren, um bei Bedarf komplexere Abfragen zu erstellen.
quelle
IQueryable
ist eine schlechte Mutter oder vielmehr eine GOTT-Schnittstelle. Die Implementierung ist sehr erfolgreich und es gibt nur sehr wenige (wenn überhaupt) vollständige LINQ to Sql-Anbieter. b) Verlängerungsmethoden machen eine Verlängerung (eines der grundlegenden OOP-Prinzipien) unmöglich.Ich habe hier ein hübsches Muster für Abfrageobjekte für NHibernate geschrieben: https://github.com/shaynevanasperen/NHibernate.Sessions.Operations
Es funktioniert mit einer Schnittstelle wie folgt:
Bei einer POCO-Entitätsklasse wie folgt:
Sie können Abfrageobjekte wie folgt erstellen:
Und dann benutze sie so:
quelle