Generisches Repository Mit EF 4.1, worum geht es?

145

Während ich mich eingehender mit DbContext, DbSet und den zugehörigen Schnittstellen befasse, frage ich mich, warum Sie für diese Implementierungen ein separates "generisches" Repository implementieren müssten.

Es sieht so aus, als ob DbContext und IDbSet alles tun, was Sie brauchen, und die "Arbeitseinheit" in DbContext aufnehmen.

Vermisse ich hier etwas oder scheint es den Leuten Spaß zu machen, ohne Grund eine weitere Abhängigkeitsebene hinzuzufügen?

Code Jammr
quelle
Dies ist ein wenig umstrittenes / meinungsbasiertes Problem. Ich habe das hier besprochen .
Amit Joshi

Antworten:

202

Du hast tatsächlich recht. DbContextist eine Implementierung des Arbeitseinheitsmusters und IDbSeteine Implementierung des Repository-Musters.

Repositories sind derzeit sehr beliebt und werden häufig verwendet. Jeder verwendet sie nur, weil es Dutzende von Artikeln zum Erstellen eines Repositorys für das Entity-Framework gibt, aber niemand beschreibt tatsächlich die Herausforderungen im Zusammenhang mit dieser Entscheidung.

Hauptgründe für die Verwendung des Repositorys sind normalerweise:

  • Verstecke EF vor der oberen Schicht
  • Machen Sie Code besser testbar

Der erste Grund ist eine Art architektonische Reinheit und eine großartige Idee, dass Sie später zu einem anderen Persistenz-Framework wechseln können, wenn Sie Ihre oberen Schichten von EF unabhängig machen. Wie oft haben Sie so etwas in der realen Welt gesehen? Dieser Grund erschwert die Arbeit mit EF erheblich, da Ihr Repository viele zusätzliche Funktionen bereitstellen muss, die das einschließen, was EF standardmäßig zulässt.

Gleichzeitig kann das Umschließen von EF-Code Ihren Code besser organisieren und die Regel der Trennung von Bedenken befolgen. Für mich kann dies der einzige wirkliche Vorteil von Repository und Arbeitseinheit sein, aber Sie müssen verstehen, dass das Befolgen dieser Regel mit EF Ihren Code möglicherweise besser wartbar und besser lesbar macht, aber bei den anfänglichen Bemühungen, Ihre Anwendung zu erstellen, viel höher und höher ist Für kleinere Anwendungen kann dies eine unnötige Komplexität sein.

Der zweite Grund ist teilweise richtig. Der große Nachteil von EF ist die starre Architektur, die kaum verspottet werden kann. Wenn Sie also die obere Schicht als Unit-Test durchführen möchten, müssen Sie EF irgendwie umschließen, damit die Implementierung verspottet werden kann. Dies hat aber noch viele andere Konsequenzen, die ich hier beschrieben habe .

Ich folge Ayendes Blog . Wenn Sie jemals NHibernate verwendet haben, kennen Sie wahrscheinlich seine Artikel. Dieser Typ hat kürzlich mehrere Artikel gegen die Verwendung von Repository mit NHibernate geschrieben, aber NHibernate ist viel besser verspottbar.

Ladislav Mrnka
quelle
3
Sie können sich lustig machen, IDbSetSie können auch eine benutzerdefinierte Schnittstelle in Ihrem abgeleiteten Kontext definieren, aber das ist alles. Sobald Ihr Code ChangeTracker, Einträge oder was auch immer verwendet, wird es einen großen Aufwand erfordern, sie alle zu verpacken.
Ladislav Mrnka
1
Ja, EF ist kein sehr leistungsorientiertes Tool. Zumindest hat MS viele Möglichkeiten, dies in zukünftigen Versionen zu verbessern.
Ladislav Mrnka
2
@chiccodoro: Richtig. Sobald Ihre verspottete Klasse jedoch einen Parameter verfügbar macht IQueryableoder Expression<>als Parameter akzeptiert , der intern in die Linq-to-Entities-Abfrage gestellt wird, definieren Sie eine Logik außerhalb der verspotteten Komponente mit Nebenwirkungen, die nicht mit Komponententests getestet werden können.
Ladislav Mrnka
8
Wenn ich DbSet und BdContext direkt in meiner Business-Schicht verwende, muss ich dort sowie in meinem DataLayer-Projekt auf EntityFramework.dll verweisen. Das allein sagt mir, dass es eine Art Verpackung braucht.
Ingó Vals
2
Downvote: unvollständig - Wenn Sie EF hinter einer Repository-Schnittstelle abstrahieren, kann genau derselbe Client-Code sowohl in SL als auch in WPF ausgeführt werden.
h.alex
21

Ich habe mit den gleichen Problemen zu kämpfen, und die Verspottbarkeit beim Testen der EF-Schichten ist wichtig. Ich bin jedoch auf diesen großartigen Artikel gestoßen, in dem erklärt wird, wie der EF 4.1 DbContext so eingerichtet wird, dass er verspottbar ist, indem sichergestellt wird, dass Ihr abgeleiteter DbContext eine generische Schnittstelle implementiert und IDbSet anstelle von DbSet verfügbar macht. Da ich einen Database First-Ansatz verwende, da unsere Datenbank bereits vorhanden ist, habe ich einfach die T4-Vorlagen geändert, die zum Generieren meines abgeleiteten DbContext verwendet wurden, um ihn zu generieren, um IDbSet-Schnittstellen zurückzugeben und von meiner generischen Schnittstelle abzuleiten. Auf diese Weise kann das Ganze leicht verspottet werden, und Sie müssen kein eigenes Arbeitseinheits- oder Repository-Muster implementieren. Schreiben Sie einfach Ihren Service-Code, um Ihre generische Schnittstelle zu nutzen, und wenn Sie zum Unit-Test gehen,

http://refactorthis.wordpress.com/2011/05/31/mock-faking-dbcontext-in-entity-framework-4-1-with-a-generic-repository/

Kendall Bennett
quelle
5

Ein Grund für das Erstellen des Repositorys besteht darin, dass Sie die Implementierung von DBSet und DbContext ausblenden können, wenn Sie von EntityFramework zu etwas anderem wechseln oder umgekehrt.

Ich habe beispielsweise NHibernate verwendet und alle Aufrufe dieses Frameworks in meine Repository-Klassen eingeschlossen. Sie geben IEnumerable zurück, damit sie "generisch" werden, und meine Repositorys verfügen über die Standard-CRUD-Operationen (Aktualisieren, Löschen usw.). Ich bin längst zu Entity Framework gewechselt. Dabei musste ich in meinen ViewModel-Klassen oder darüber hinaus nichts mehr ändern, da sie auf mein Repository verweisen. Ich musste nur das Innere meines Repositorys ändern. Dies erleichterte das Leben bei der Migration erheblich.

(Ich habe NHibernate verwendet, weil wir eine Verbindung zu den ISeries herstellen, und zu diesem Zeitpunkt gab es keine kosteneffektiven Implementierungen mit EF mit den ISeries. Die einzige verfügbare war, IBM 12.000 US-Dollar für ihren DB2Connect zu zahlen.)

Leniel Maccaferri
quelle
"Fast" (beim Ausblenden von DBSet und DbContext) werden Sie feststellen, dass Sie EF keinem Verbraucher zugänglich machen müssen (z. B. wenn Sie DI nutzen), sondern eine Schnittstelle benötigen, die IDbSet <T> -Eigenschaften oder Gehen Sie noch einen Schritt weiter und geben Sie stattdessen alle Ihre Eigenschaften als IQueryable <T> ein. Mein Punkt ist jedoch, dass Sie Ihre Abhängigkeit von DbSet und DbContext vollständig verbergen können. CRUD-Operationen können dann als Erweiterungsmethoden geschrieben werden. Sie können mehrere Erweiterungsmethoden für verschiedene Sicherungsspeicher schreiben. Sie würden die Verwendung von LINQ jedoch nicht verbergen.
Shaun Wilson