Ich habe kürzlich gelesen, dass es nicht empfehlenswert ist, das Repository-Muster in Verbindung mit einem ORM zu verwenden. Nach meinem Verständnis liegt dies daran, dass die Abstraktion, die sie über die SQL-Datenbank bereitstellen, zu undicht ist, um im Muster enthalten zu sein.
Ich habe ein paar Fragen dazu:
Was machen Sie, wenn Sie ORMs austauschen möchten? Sie würden ORM-spezifischen Code in Ihrer Anwendung haben, wenn Sie ihn nicht in einem Repository enthalten.
Ist das Repository-Muster auch dann noch gültig, wenn Sie kein ORM verwenden und ADO.NET für den Datenzugriff und das Auffüllen von Objektdaten selbst verwenden?
Wenn Sie ein ORM verwenden, aber nicht das Repository-Muster, wo speichern Sie häufig verwendete Abfragen? Wäre es sinnvoll, jede Abfrage als Klasse darzustellen und eine Art Abfragefactory zum Erstellen von Instanzen zu haben?
quelle
Antworten:
1) Stimmt, aber wie oft schalten Sie einen ORM aus?
2) Ich würde es so sagen, weil ein ORM-Kontext eine Art Repository ist und eine Menge Arbeit verbirgt, die das Erstellen von Abfragen, das Abrufen von Daten, das Zuordnen usw. umfasst. Wenn Sie kein ORM verwenden, muss sich diese Logik immer noch irgendwo befinden. Ich weiß nicht, ob dies als Repository-Muster im engeren Sinne des Wortes in
Frage kommen würde. 3) Das Einkapseln von Abfragen ist etwas, das ich häufig sehe, aber normalerweise eher zu Test- / Stubbing-Zwecken. Ansonsten wäre ich vorsichtig, wenn Sie eine Abfrage über verschiedene Teile einer Anwendung hinweg wiederverwenden, da Sie die Gefahr haben, eine Abhängigkeit von etwas zu erzeugen, das sich n-mal ändern könnte (n ist die Anzahl der Stellen, an denen Sie die Abfrage verwenden).
quelle
Ich war noch nicht in einer Position, in der das Unternehmen plötzlich beschlossen hat, die Datenzugriffstechnologie zu wechseln. In diesem Fall sind einige Arbeiten erforderlich. Ich tendiere dazu, Datenzugriffsoperationen über Schnittstellen zu abstrahieren. Repository ist eine Möglichkeit, dies zu lösen.
Ich hätte dann eine andere Assembly für die konkrete Implementierung meiner Datenzugriffsebene. Zum Beispiel könnte ich haben:
Company.Product.Data
undCompany.Product.Data.EntityFramework
Baugruppen. Die erste Assembly würde nur für Schnittstellen verwendet, während eine andere eine konkrete Implementierung der Datenzugriffslogik von Entity Framework wäre.Ich denke, es liegt an Ihnen, zu entscheiden, welches Muster gültig ist oder nicht. Ich habe ein Repository-Muster in der Präsentationsebene verwendet. Eine Sache, an die man denken sollte, ist, dass die Leute gerne Verantwortung in die Repositories werfen. Bevor Sie es wissen, wird Ihre Repository-Klasse tanzen, singen und alle möglichen Dinge tun. Sie möchten dies vermeiden.
Ich habe eine Repository-Klasse gesehen, die zu Beginn die Zuständigkeiten GetAll, GetById, Update und Delete hatte, was in Ordnung ist. Zu dem Zeitpunkt, als das Projekt abgeschlossen war, verfügte dieselbe Klasse über Dutzende von Methoden (Verantwortlichkeiten), die niemals hätten da sein dürfen. Zum Beispiel GetByForename, GetBySurname, UpdateWithExclusions und alle möglichen verrückten Sachen.
Hier kommen Abfragen und Befehle ins Spiel.
Ich halte es für eine sehr gute Idee, Abfragen und Befehle anstelle von Repositorys zu verwenden. Ich mache folgendes:
Schnittstelle für eine Abfrage definieren. Dies wird Ihnen beim Unit-Test helfen. Z.B
public interface IGetProductsByCategoryQuery { ... }
Definieren Sie eine konkrete Implementierung für eine Abfrage. Sie können diese über ein IoC-Framework Ihrer Wahl einspeisen. Z.B
public class GetProductsByCategoryQuery : IGetProductsByCategoryQuery
Anstatt das Repository mit Dutzenden von Verantwortlichkeiten zu verschmutzen, gruppiere ich meine Abfragen einfach in Namespaces. Beispielsweise kann eine Schnittstelle für die obige Abfrage in:
Company.SolutionName.Products.Queries
und die Implementierung in lebenCompany.SolutionName.Products.Queries.Implementation
Wenn es um das Aktualisieren oder Entfernen von Daten geht, verwende ich das Befehlsmuster auf die gleiche Weise.
Einige mögen anderer Meinung sein und sagen, dass Sie Dutzende von Klassen und Namespaces haben werden, bevor das Projekt abgeschlossen ist. Ja du wirst. In meinen Augen ist es eine gute Sache, wenn Sie die Lösung in der IDE Ihrer Wahl durchsuchen und sofort sehen können, welche Art von Verantwortlichkeiten eine bestimmte Komponente hat. Wenn Sie sich stattdessen für die Verwendung eines Repository-Musters entschieden haben, müssen Sie in jeder Repository-Klasse nachsehen, um die Verantwortlichkeiten herauszufinden.
quelle
HAFTUNGSAUSSCHLUSS: Was folgt, basiert auf meinem Verständnis und meiner kurzen Erfahrung mit diesem Muster (dh Repository). Ich könnte es falsch machen ... in der Tat bin ich mir ziemlich sicher, dass ich es falsch mache :). Während dies also ein Versuch zur Beantwortung ist, handelt es sich auch um eine verdeckte Frage.
Ich verwende das Repository-Muster, um die Datenzugriffsebene zu abstrahieren, die in den meisten Fällen ein ORM ist. Es handelt sich um eine generische Schnittstelle mit Methoden für die Klassen "Erstellen", "Lesen", "Aktualisieren", "Löschen" und "Implementieren" für LINQ to SQL und EF. Ich könnte eine Implementierung erstellen, die in XML-Dateien auf der Festplatte schreibt (nur ein wildes Beispiel dafür, was ich damit machen könnte). Ich implementiere Unit of Work nicht, da es von den ORMs unterstützt wird. Notfalls könnte ich es wohl umsetzen. Ich mag es so, weil es mir bisher eine schöne Trennung gegeben hat. Ich sage nicht, dass es keine besseren Alternativen gibt.
Um Ihre Fragen zu beantworten:
Um Ihnen ein weiteres Beispiel zu geben: Die Mitarbeiter von Umbraco haben den DI-Container entfernt, nur für den Fall, dass sie zu etwas anderem wechseln möchten.
quelle
Wenn der ORM die Flexibilität von LINQ, eifriges Laden usw. bietet, würde ich ihn nicht hinter einer zusätzlichen Ebene verstecken.
Wenn es sich um Raw-SQL (Micro-ORM) handelt, sollte ohnehin "Methode pro Abfrage" verwendet werden, um die Wiederverwendbarkeit zu erreichen, sodass das Repository-Muster gut passt.
Warum müssten Sie wechseln?
Es sollte das verwendet werden, das die meisten Funktionen bietet, die Sie benötigen. Es ist möglich, dass eine neue Version von ormX neue Funktionen bringt und sich als besser herausstellt als die aktuelle, aber ...
Wenn Sie sich dafür entscheiden, das Orm auszublenden, können Sie nur die Funktionen verwenden, die alle Kandidaten gemeinsam haben.
Sie können z. B. keine
Dictionary<string, Entity>
Eigenschaften in Ihren Entitäten verwenden, weil ormY diese nicht verarbeiten kann.Vorausgesetzt, LINQ wird verwendet, wechselt die Mehrheit der orm-Switches lediglich die Bibliotheksreferenzen und ersetzt sie
session.Query<Foo>()
durchcontext.Foos
oder ähnliches, bis sie kompiliert werden. Langweilige Aufgabe, benötigt aber weniger Zeit als das Codieren der Abstraktionsschicht.Ja. Code sollte wiederverwendbar sein und das bedeutet, SQL-Gebäude, Objektmaterialisierung usw. an einem Ort zu platzieren (separate Klasse). Sie können auch die Klasse "XRepository" aufrufen und eine Schnittstelle daraus extrahieren.
Unter der Annahme, dass LINQ verwendet wird, wäre ein Klassenwrapper meiner Meinung nach übertrieben. Eine schönere Möglichkeit wären Erweiterungsmethoden
Jeder Code, der an mehreren Stellen verwendet wird (oder das Potenzial hat) und kompliziert genug ist (fehleranfällig), sollte an einer zentralen Stelle extrahiert werden.
quelle