Repository-Muster vs DAL


93

Sind sie dasselbe? Ich bin gerade fertig, um Rob Connerys Storefront-Tutorial anzusehen, und es scheint sich um ähnliche Techniken zu handeln. Ich meine, wenn ich ein DAL-Objekt implementiere, habe ich die Methoden GetStuff, Add / Delete usw. und schreibe immer zuerst die Schnittstelle, damit ich später die Datenbank wechseln kann.

Verwechsle ich die Dinge?

Antworten:


88

Du bist definitiv nicht derjenige, der die Dinge verwirrt. :-)

Ich denke, die Antwort auf die Frage hängt davon ab, wie sehr Sie ein Purist sein wollen.

Wenn Sie eine strikte DDD-Sichtweise wünschen, führt Sie dies auf einen Weg. Wenn Sie das Repository als ein Muster betrachten, das uns geholfen hat, die Schnittstelle der Schicht, die zwischen den Diensten und der Datenbank trennt, zu standardisieren, werden Sie durch ein anderes heruntergefahren.

Das Repository ist aus meiner Sicht nur eine klar festgelegte Ebene für den Zugriff auf Daten. Mit anderen Worten, eine standardisierte Methode zur Implementierung Ihrer Datenzugriffsebene. Es gibt einige Unterschiede zwischen verschiedenen Repository-Implementierungen, aber das Konzept ist das gleiche.

Einige Benutzer legen mehr DDD-Einschränkungen für das Repository fest, während andere das Repository als bequemen Vermittler zwischen der Datenbank und der Serviceschicht verwenden. Ein Repository wie ein DAL isoliert die Serviceschicht von den Datenzugriffsspezifikationen.

Ein Implementierungsproblem, das sie zu unterscheiden scheint, besteht darin, dass ein Repository häufig mit Methoden erstellt wird, die eine Spezifikation annehmen. Das Repository gibt Daten zurück, die dieser Spezifikation entsprechen. Die meisten traditionellen DALs, die ich gesehen habe, haben einen größeren Satz von Methoden, bei denen die Methode eine beliebige Anzahl von Parametern akzeptiert. Dies mag nach einem kleinen Unterschied klingen, ist jedoch ein großes Problem, wenn Sie die Bereiche Linq und Expressions betreten. Unsere Standard-Repository-Oberfläche sieht folgendermaßen aus:

public interface IRepository : IDisposable
{
    T[] GetAll<T>();
    T[] GetAll<T>(Expression<Func<T, bool>> filter);
    T GetSingle<T>(Expression<Func<T, bool>> filter);
    T GetSingle<T>(Expression<Func<T, bool>> filter, List<Expression<Func<T, object>>> subSelectors);
    void Delete<T>(T entity);
    void Add<T>(T entity);
    int SaveChanges();
    DbTransaction BeginTransaction();
}

Ist das ein DAL oder ein Repository? In diesem Fall denke ich, dass es beides ist.

Kim


5
Spät zur Party hier, aber warum T [], nicht List <T> (oder ähnliches)?
Mike Kingscott

27
Vielleicht wäre IEnumerable <T> das Beste.
Venemo

9
oder IQueryable <T>
Kenwarner

1
Ich denke, IQueryable <T> wäre die beste Wahl, da Sie damit Methoden verketten und die Ausführung verschieben können, sodass die Datenbank die gesamte Arbeit erledigen kann.
0lukasz0

4
@kenwarner Ich denke, dass die Rückgabe von IQueryable <T> die Abstraktion verliert. Sie sollten Domänenobjekte aus Ihrem Repository zurückgeben.
Matthew

42

Ein Repository ist ein Muster, das auf viele verschiedene Arten angewendet werden kann, während die Datenzugriffsschicht eine sehr klare Verantwortung trägt: Der DAL muss wissen, wie er sich mit Ihrem Datenspeicher verbindet, um CRUD-Operationen auszuführen.

Ein Repository kann ein DAL sein, es kann sich jedoch auch vor dem DAL befinden und als Brücke zwischen der Geschäftsobjektschicht und der Datenschicht fungieren. Welche Implementierung verwendet wird, wird von Projekt zu Projekt unterschiedlich sein.


23

Ein großer Unterschied besteht darin, dass ein DAO eine generische Methode ist, um mit der Persistenz für jede Entität in Ihrer Domäne umzugehen. Ein Repository behandelt dagegen nur aggregierte Wurzeln.


26
Das erste, was zu verstehen ist, ist, dass ein Repository als Muster Teil des größeren Systems ist, das als Domain Driven Design bekannt ist. In der DDD-Domäne werden Objekte in Aggregate mit jeweils einem Aggregatstamm gruppiert. Beispiel: PurchaseOrder ist ein aggregierter Stamm und OrderItems sind untergeordnete Elemente im aggregierten Stamm. Ein Repository behandelt nur aggregierte Wurzeln. Das heißt, ein OrderItem wird beispielsweise niemals unabhängig von seinem aggreate-Stamm geladen. Sie würden also niemals ein OrderItem-Repository in DDD haben. In einem Nicht-DDD-System können Sie jedoch ein OrderItemDao haben, da Dao nicht auf aggregierte Roots beschränkt ist.
pondermatischer

NG, danke! Ich hatte angefangen, es so zu sehen, aber das macht es klar. Ich muss anfangen, die gesamte DDD-Literatur zu lesen!
David

@bingle, großartige Beschreibung der aggregierten Wurzeln und wie untergeordnete Objekte von einem Repository geladen werden. Wo würde ein Repository in einer mehrschichtigen Anwendung existieren? Ich konnte sehen, dass es sich in einer Datenzugriffsschichtbibliothek befindet, aber sollte es stattdessen in der Logikschichtbibliothek vorhanden sein, da es untergeordnete Objekte lädt? Mein Bauch sagt mir die Datenzugriffsschicht, aber ich wollte Ihre Meinung zu diesem Thema.
Jeff LaFay

12

Ich suchte nach einer Antwort auf eine ähnliche Frage und stimmte den beiden am höchsten bewerteten Antworten zu. Als ich versuchte, dies für mich selbst zu klären, stellte ich fest, dass ich es kann, wenn Spezifikationen, die mit dem Repository-Muster Hand in Hand gehen, als erstklassige Mitglieder des Domänenmodells implementiert werden

  • Wiederverwendung von Spezifikationsdefinitionen mit unterschiedlichen Parametern,
  • Bearbeiten Sie die Parameter vorhandener Spezifikationsinstanzen (z. B. um sich zu spezialisieren).
  • kombiniere sie,
  • Führen Sie eine Geschäftslogik auf ihnen durch, ohne jemals auf eine Datenbank zugreifen zu müssen.
  • und testen Sie sie natürlich unabhängig von den tatsächlichen Repository-Implementierungen.

Ich kann sogar so weit gehen und sagen, dass es nicht wirklich "Repository" ist, sondern ein DAL , wenn das Repository-Muster nicht zusammen mit dem Spezifikationsmuster verwendet wird. Ein erfundenes Beispiel im Pseudocode:

specification100 = new AccountHasMoreOrdersThan(100)
specification200 = new AccountHasMoreOrdersThan(200)

assert that specification200.isSpecialCaseOf(specification100)

specificationAge = new AccountIsOlderThan('2000-01-01')

combinedSpec = new CompositeSpecification(
    SpecificationOperator.And, specification200, specificationAge)

for each account in Repository<Account>.GetAllSatisfying(combinedSpec)
    assert that account.Created < '2000-01-01'
    assert that account.Orders.Count > 200

Weitere Informationen finden Sie in Fowlers Spezifikationsaufsatz (darauf habe ich das oben Gesagte gestützt).

Ein DAL hätte spezielle Methoden wie

IoCManager.InstanceFor<IAccountDAO>()
    .GetAccountsWithAtLeastOrdersAndCreatedBefore(200, '2000-01-01')

Sie können sehen, wie schnell dies umständlich werden kann, zumal Sie mit diesem Ansatz jede der DAL / DAO-Schnittstellen definieren und die DAL-Abfragemethode implementieren müssen.

In .NET, LINQ - Abfragen können ein Weg sein , Spezifikationen zu implementieren, aber die Kombination von Specification (Ausdrücke) nicht wie mit einer home-grown - Lösung glatt sein. Einige Ideen dazu sind in dieser SO-Frage beschrieben .


2

Meine persönliche Meinung ist, dass es nur um Mapping geht, siehe: http://www.martinfowler.com/eaaCatalog/repository.html . Die Ausgabe / Eingabe aus dem Repository sind also Domänenobjekte, die auf der DAL alles sein können. Für mich ist dies eine wichtige Ergänzung / Einschränkung, da Sie eine Repository-Implementierung für eine Datenbank / einen Dienst / was auch immer mit einem anderen Layout hinzufügen können und sich klar auf die Zuordnung konzentrieren können. Wenn Sie diese Einschränkung nicht verwenden und die Zuordnung nicht an anderer Stelle verwenden, kann die unterschiedliche Darstellung von Daten den Code an Stellen beeinflussen, an denen er nicht geändert werden sollte.


1

Es geht um Interpretation und Kontext. Sie können sehr ähnlich oder sogar sehr unterschiedlich sein, aber solange die Lösung den Job macht, was steckt in einem Namen!


1

Repository ist ein Muster. Dies ist eine Möglichkeit, die Dinge auf standardisierte Weise zu implementieren, um den Code so weit wie möglich wiederzuverwenden.


1

Der Vorteil der Verwendung eines Repository-Musters besteht darin, dass Sie Ihre Datenzugriffsschicht verspotten, sodass Sie Ihren Business-Layer-Code testen können, ohne DAL-Code aufzurufen. Es gibt andere große Vorteile, aber dies scheint mir sehr wichtig zu sein.


1
Sie können einen DAL immer noch verspotten, es muss kein Repository an sich sein. Der wichtige Punkt ist, dass unabhängig von der verwendeten Datenzugriffsstrategie eine Schnittstelle implementiert werden sollte. Auf diese Weise können Sie IoC-Container verwenden und Ihren Geschäftscode sauber testen, ohne einen Datenspeicher zu benötigen.
cdaq

0

Soweit ich weiß, können sie im Grunde dasselbe bedeuten - aber die Benennung variiert je nach Kontext.

Beispielsweise könnten Sie eine Dal / Dao-Klasse haben, die eine IRepository-Schnittstelle implementiert.

Dal / Dao ist ein Datenschichtbegriff. Die höheren Ebenen Ihrer Anwendung denken in Repositorys.


0

In den meisten (einfachen) Fällen ist DAO also eine Implementierung von Repository?

Soweit ich weiß, scheint sich DAO genau mit dem Datenbankzugriff zu befassen (CRUD - Keine Auswahl?!), Während das Repository es Ihnen ermöglicht, den gesamten Datenzugriff zu abstrahieren, möglicherweise als Fassade für mehrere DAO (möglicherweise unterschiedliche Datenquellen).

Bin ich auf dem richtigen Weg?


Eigentlich würde ich das umkehren und sagen, dass ein Repository aus vereinfachender Sicht ein bestimmter Implementierungsstil für ein DAO ist, aber ja, Sie sind auf dem richtigen Weg. (R von CRUD = Lesen, das ist also Ihre Auswahl.)
Jeromy Irvine

0

In der Außenwelt (dh im Clientcode) ist das Repository mit DAL identisch, außer:

(1) Die Einfüge- / Aktualisierungs- / Löschmethode ist darauf beschränkt, das Datencontainerobjekt als Parameter zu verwenden.

(2) Für den Lesevorgang kann eine einfache Spezifikation wie eine DAL (zum Beispiel GetByPK) oder eine erweiterte Spezifikation erforderlich sein.

Intern arbeitet es mit einer Data Mapper-Schicht (z. B. Entity Framework-Kontext usw.), um die eigentliche CRUD-Operation auszuführen.

Welches Repository-Muster bedeutet nicht: -

Ich habe auch gesehen, dass die Leute oft verwirrt sind, eine separate Save-Methode als Beispielimplementierung für das Repository-Muster neben den Insert / Update / Delete-Methoden zu haben, die alle speicherinternen Änderungen festlegt, die durch Insert / Update / Delete-Methoden in der Datenbank vorgenommen werden. Wir können definitiv eine Save-Methode in einem Repository haben, aber das liegt nicht in der Verantwortung des Repositorys, die speicherinternen CUD- (Create, Update, Delete) und Persistenzmethoden (die den eigentlichen Schreib- / Änderungsvorgang in der Datenbank ausführen) zu isolieren, sondern die Verantwortung für das Muster der Arbeitseinheit.

Hoffe das hilft!


0

Man könnte argumentieren, dass ein "Repository" eine bestimmte Klasse ist und ein "DAL" die gesamte Schicht ist, die aus den Repositorys, DTOs, Dienstprogrammklassen und allem anderen, was erforderlich ist, besteht.

Durch die Nutzung unserer Website bestätigen Sie, dass Sie unsere Cookie-Richtlinie und Datenschutzrichtlinie gelesen und verstanden haben.
Licensed under cc by-sa 3.0 with attribution required.