Es gibt eine Frage zum IRepository und wofür es verwendet wird, hat eine scheinbar gute Antwort.
Mein Problem allerdings: Wie würde ich sauber mit Entitäten umgehen, die miteinander verwandt sind, und ist nicht IRepository dann nur eine Ebene ohne wirklichen Zweck?
Nehmen wir an, ich habe diese Geschäftsobjekte:
%Vor%Es gibt Regeln:
Wie würde mein RegionRepository aussehen?
%Vor%Wie Sie sehen, muss ein RegionRepository ebenfalls Standorte abrufen. In meinem Beispiel verwende ich Linq To Sql EntitySet / EntireyRef, aber jetzt muss Region mit Mapping Locations zu Business Objects umgehen (weil ich zwei Gruppen von Objekten, Business- und L2S-Objekten habe).
Soll ich das zu etwas umgestalten wie:
%Vor%Nun habe ich meine Datenschicht schön in atomare Repositories aufgeteilt, die jeweils nur einen Typ haben. Ich feuere den Profiler und ... Whoops, SELECT N + 1. Weil jede Region den Standortdienst aufruft. Wir haben nur ein Dutzend Regionen und ungefähr 40 Standorte, also ist die natürliche Optimierung die Verwendung von DataLoadOptions . Das Problem ist, dass das RegionRepository nicht weiß, ob LocationRepository denselben DataContext verwendet oder nicht. Wir injizieren doch Fabriken hierhin, also könnte LocationRepository selbstständig werden. Und selbst wenn dies nicht der Fall ist - ich rufe eine Service-Methode auf, die Business-Objekte zur Verfügung stellt, so dass die DataLoadOptions trotzdem nicht verwendet werden dürfen.
Ah, ich habe etwas übersehen. IRepository soll eine Methode wie folgt haben:
%Vor%Also würde ich jetzt
machen %Vor% Das sieht gut aus. Zu Beginn. Bei der zweiten Inspektion habe ich separate Business- und L2S-Objekte, daher sehe ich immer noch nicht, wie dies SELECT N + 1 vermeidet, da Query nicht nur GetTable<DbLocation>
zurückgeben kann.
Das Problem scheint zwei verschiedene Objektgruppen zu haben. Aber wenn ich Business Objects mit allen Attributen von System.Data.LINQ ausstatte ([Table], [Column] usw.), bricht das die Abstraktion und vereitelt den Zweck von IRepository. Da ich vielleicht auch ein anderes ORM verwenden möchte, müsste ich nun meine Business Entities mit anderen Attributen ausstatten (auch wenn die Business Entities in einer separaten .Business-Assembly sind, müssen die Konsumenten dies jetzt tun) Verweise auf alle ORMs auch auf die zu lösenden Attribute - yuck!).
Mir scheint, dass IRepository IService sein sollte, und die obige Klasse sollte so aussehen:
%Vor%Dies löst auch ein Hühnerei-Problem:
Dies ist ohne EntitySet praktisch unmöglich. Wenn Sie also die Datenintegrität in der Datenbank nicht opfern und in die Geschäftslogik verschieben, ist es unmöglich, die Verantwortung für Standorte außerhalb des Region-Anbieters zu behalten.
Ich sehe, wie dieser Beitrag als keine echte, subjektive und argumentative Frage gesehen werden kann. Gestatten Sie mir deshalb, eine objektive Frage zu formulieren:
Ich denke, meine eigentliche Frage ist:
Beim Entwerfen Ihrer Repositories sollten Sie über den so genannten Aggregatstamm nachdenken. Im Wesentlichen bedeutet dies, dass, wenn eine Entität alleine in der Domäne existieren kann, sie mehr als nur ein eigenes Repository haben wird. In Ihrem Fall wäre das die Region.
Betrachten Sie das klassische Kunden / Auftrags-Szenario. Das Kundenrepository würde den Zugriff auf Bestellungen ermöglichen, da eine Bestellung ohne einen Kunden nicht existieren kann. Daher ist es unwahrscheinlich, dass Sie ein separates Bestellrepository benötigen, sofern Sie keinen gültigen Geschäftsfall haben.
In einer einfachen Anwendung mag Ihre Annahme richtig sein, aber denken Sie daran, dass Sie, solange Sie nicht eine Abstraktion Ihres L2S-Kontextes bereitstellen, Schwierigkeiten haben, effektive Komponententests durchzuführen. Kodierung gegen eine Schnittstelle, sei es eine IServiceX, IRepositoryX oder was auch immer, bietet Ihnen diese Ebene der Trennung.
Die Entscheidung, ob Service-Interfaces in das Design einfließen, hängt in der Regel wieder mit der Komplexität der Geschäftslogik und der Notwendigkeit einer erweiterbaren Api in diese Logik zusammen, die möglicherweise von mehreren unterschiedlichen Clients verwendet wird.
Ich habe mehrere Gedanken über all das: 1. Das AFAIK-Repository-Muster wurde etwas früher als das ORM erfunden. Früher war es bei einfachen SQL-Abfragen eine gute Idee, das Repository zu implementieren und diesen abstrakten Code von der tatsächlich verwendeten Datenbank zu kaufen. 2. Ich könnte sagen, dass Repository jetzt nicht benötigt wird, aber leider kann ich aus meiner Erfahrung nicht sagen, dass jedes ORM Sie wirklich von allen Datenbankdetails abstrahieren kann. Z.B. Ich konnte nicht einmal ein ORM-Mapping erstellen und es nur mit jedem anderen DB-Server verwenden, den ORM zu unterstützen (insbesondere ich spreche über Microsoft EF). Wenn Sie also wirklich verschiedene Datenbankserver verwenden möchten, müssen Sie wahrscheinlich Repository verwenden. 3. Ein weiteres Problem ist sehr einfach: Code-Duplizierung. Sicher gibt es einige Abfragen, die Sie häufig Ihren Code aufrufen. Wenn Sie nur ORM als Repository beibehalten, dann werden Sie diese Abfragen duplizieren, so dass es besser ist, eine gewisse Abstraktionsebene über dem ORM-Container zu haben, der diese häufig verwendeten Abfragen enthält.
Tags und Links .net linq-to-sql repository-pattern