12

Ich habe ein Problem mit Repository-Muster - wie Sie JOIN-Operationen zwischen mehreren Repositories durchführen. In diesem Projekt verwenden wir MVC, EF, DDD. Ich bin mir bewusst, dass diese Art von Frage hier mehrere Male war, ich verweise später auf diese Fragen in diesem.Repository-Muster - wie JOINs und komplexe Abfragen korrekt behandelt werden?

Zwischen dem generischen Repository-Modell (IRepository) und dem spezifischen Repository-Modell wähle ich eine spezifische Option, da ich ORM (in unserem Fall EF) als generisches Repository-Muster ansehe, sodass es nicht sinnvoll ist, ein anderes generisches Repository hinzuzufügen und wir würden das Repository eher an die Domain-Bedürfnisse anpassen.

Das Problem ist, dass ich mehrere (~ 10) Tabellen mit jeweils vielen Zeilen (Millionen) habe, und ich muss JOINs durchführen, also ist die Verwendung von IList oder IEnumerable keine praktikable Option.

Mein Verständnis (und meine Perspektive) ist, dass IQueryable das Repository nicht verlassen sollte ("Was in DAL passiert, sollte in DAL bleiben."). Es wäre viel einfacher, IQueryable zu offenbaren und es in LINQ im Dienst zu verwenden, aber es verletzt stark die Trennung von Bedenken und untergräbt die Rolle von Repositories - in diesem Fall wird der Dienst das selbe tun wie das Repository. Um nur einige zu holen, diese Artikel diese Perspektive sichern (oder eher Überzeugung):

To return IQueryable<T> or not return IQueryable<T>

Should I return IEnumerable<T> or IQueryable<T> from my DAL?

http://www.shawnmclean.com/blog/2011/06/iqueryable-vs-ienumerable-in-the-repository-pattern/

http://blog.ploeh.dk/2012/03/26/IQueryableTisTightCoupling/

Darüber hinaus gibt es ähnliche Fragen und Lösungen, z.B. How to join Multiple tables using Repository Pattern & Entity Framework?, die .Include() vorschlagen, aber dies ist keine Option für schwer geladene Tabellen und Joins über viele Tabellen hinweg - mit jedem JOIN verwenden wir Subselects, um zu begrenzen, was tatsächlich verbunden ist.

Diese Frage (die Antwort und Kommentare) - How can I query cross tables with Repository Pattern? - im Grunde schlägt aufgabenbasierte Differenzierung: Erstellen eines Repository für Abfragen mit JOINS und "normalen" Repositories für die Manipulation mit jeder Entität.

Ich sehe wir haben folgende Möglichkeiten:

  1. IQueryable Belichtungs- und komplexe Abfragen in Diensten Durchführung JOIN; Ich fühle aufrichtig, dass es Anti-Pattern ist, das mag ich nicht.
  2. Verwenden Sie für diese ~ 10 Tabellen kein Repository und führen Sie keine Abfragen in Diensten durch; Einige Artikel vorgeschlagen, dass die Verwendung von EF ist genug (z. B. Is it okay to bypass the repository pattern for complex queries?), stimme ich nicht damit überein.
  3. Verwenden Sie aufgabenbasierte Differenzierung, begrenzen Sie Repositories nicht 1: 1 repo: entity (Ich bin für diese Option)
  4. Etwas ganz anderes?

Also - was würden Sie vorschlagen? Immer wieder danke.

+1

Der Punkt des Umgangs mit einem Repository besteht darin, die db alle zusammen zu ignorieren. DB-Engines, Tabellen, SQL, Joins usw. sind Implementierungsdetails eines Repositorys, die niemals die Persistenzgrenze überschreiten. SO kennt die App niemals EF oder Joins und greift niemals direkt auf die db zu. Die App weiß nur über das Repository und es sagt ** was ** zu tun/nicht ** wie ** es zu tun – MikeSW

+0

Hallo Robert, ich habe mit dem gleichen Problem zu kämpfen. Was ich bisher herausgefunden habe, brachte mich zu dem gleichen Schluss, den Sie mit den Optionen hatten. Welchen Ansatz verfolgen Sie am Ende und warum? –

+1

Hallo, für komplexe Abfragen verwenden wir einige spezifische Repositories nur für Abfragen, und in unserem Fall werden Abfragen in diesen Repositories normalerweise von gespeicherten Prozeduren ausgeführt, die mehrere Datensätze zurückgeben (wenn join nicht genug ist) und das Repository übersetzt dies in spezifische (in der Regel komplexer) Domain-Objekt (das ist keine Entität per se, aber ich glaube, es ist immer noch nicht Missbrauch von DDD). –

Antwort

14
  1. bedeutet ausbleibende Persistenz in Anwendung - Antipattern, Spaghetti-Code.
  2. wie unterscheidet es sich genau von (1)? Immer noch das gleiche Problem.
  3. ein bisschen näher ...
  4. Verwenden Sie Abfrage Objekt Muster.Verkapseln Sie Ihre komplexe Abfrage in einem aufgabenbasierten Objekt, das sich neben Repositorys befindet. Es kann DTOs zurückgeben, die für Ansichten und nicht für Domänenobjekte optimiert sind.
  5. Wenn Sie sich stark auf QO verlassen, gelangen Sie zu einer Architektur namens CQRS - Command-Query Responsibility Segregation.

Eine weitere Sache. Es gibt keine 1: 1 Übereinstimmung für die Entität: Repo. Nur Aggregate sollten ein Repository haben, nicht jede einzelne Entität.