Wzorzec repozytorium a DAL


Odpowiedzi:


88

Na pewno nie jesteś tym, który myli rzeczy. :-)

Myślę, że odpowiedź na to pytanie zależy od tego, jak bardzo chcesz być purystą.

Jeśli chcesz mieć ścisły punkt widzenia DDD, zaprowadzi cię to jedną ścieżką. Jeśli spojrzysz na repozytorium jako wzorzec, który pomógł nam ustandaryzować interfejs warstwy oddzielającej usługi od bazy danych, spowoduje to przejście do kolejnej.

Z mojej perspektywy repozytorium to tylko jasno określona warstwa dostępu do danych, czyli ustandaryzowany sposób implementacji Twojej warstwy dostępu do danych. Istnieją pewne różnice między różnymi implementacjami repozytoriów, ale koncepcja jest taka sama.

Niektórzy ludzie będą nakładać na repozytorium więcej ograniczeń DDD, podczas gdy inni będą używać repozytorium jako wygodnego pośrednika między bazą danych a warstwą usług. Repozytorium, takie jak DAL, izoluje warstwę usług od specyfiki dostępu do danych.

Jedną z kwestii implementacji, która wydaje się je odróżniać, jest to, że repozytorium jest często tworzone za pomocą metod, które wymagają specyfikacji. Repozytorium zwróci dane, które spełniają tę specyfikację. Większość tradycyjnych DAL, które widziałem, będzie miała większy zestaw metod, w których metoda będzie wymagała dowolnej liczby parametrów. Chociaż może to brzmieć jak mała różnica, jest to duży problem, gdy wchodzisz w sferę Linq i Expressions. Nasz domyślny interfejs repozytorium wygląda następująco:

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();
}

Czy to jest DAL czy repozytorium? W tym przypadku chyba oba.

Kim


5
Spóźniłem się na imprezę tutaj, ale dlaczego T [], a nie List <T> (lub podobny)?
Mike Kingscott

27
Być może IEnumerable <T> byłby najlepszy.
Venemo

9
lub IQueryable <T>
kenwarner

1
Myślę, że IQueryable <T> byłby najlepszym wyborem, ponieważ pozwala łączyć metody i odraczać wykonanie, pozwalając bazie danych na wykonanie całej pracy.
0lukasz0

4
@kenwarner Myślę, że powrót IQueryable <T> przecieka abstrakcję. Powinieneś zwrócić obiekty domeny ze swojego repozytorium.
Matthew

42

Repozytorium to wzorzec, który można zastosować na wiele różnych sposobów, podczas gdy warstwa dostępu do danych ma bardzo wyraźną odpowiedzialność: DAL musi wiedzieć, jak połączyć się z magazynem danych, aby wykonywać operacje CRUD.

Repozytorium może być DAL, ale może również znajdować się przed DAL i działać jako pomost między warstwą obiektu biznesowego a warstwą danych. To, która implementacja jest używana, będzie się różnić w zależności od projektu.


23

Jedną dużą różnicą jest to, że DAO to ogólny sposób radzenia sobie z trwałością dla dowolnej jednostki w Twojej domenie. Z drugiej strony repozytorium zajmuje się tylko zagregowanymi korzeniami.


26
Pierwszą rzeczą do zrozumienia jest to, że repozytorium jako wzorzec jest częścią większego systemu znanego jako Domain Driven Design. W domenie DDD obiekty są pogrupowane w agregaty, z których każdy ma zbiorczy katalog główny. Np. PurchaseOrder to zagregowany katalog główny, a OrderItems to elementy podrzędne w zbiorczym katalogu głównym. Repozytorium obsługuje tylko zbiorcze korzenie. Oznacza to, że na przykład OrderItem nigdy nie jest ładowany niezależnie od jego agregatu głównego. Więc nigdy nie miałbyś repozytorium OrderItem w DDD. Jednak w systemie innym niż DDD można mieć element OrderItemecomm, ponieważ Dao nie jest ograniczony do zagregowanych korzeni.
pondermatic

NG, dzięki! Zacząłem postrzegać to w ten sposób, ale to wyjaśnia. Muszę zacząć czytać całą literaturę DDD!
David

@bingle, świetny opis zbiorczych korzeni i sposobu ładowania obiektów podrzędnych przez repozytorium. Gdzie istniałoby repozytorium w wielowarstwowej aplikacji? Widziałem, że znajduje się w bibliotece warstw dostępu do danych, ale ponieważ ładuje obiekty podrzędne, czy zamiast tego powinien istnieć w bibliotece warstw logicznych? Moje przeczucie podpowiada mi warstwę dostępu do danych, ale chciałem poznać Twoją opinię w tej sprawie.
Jeff LaFay,

12

Szukałem odpowiedzi na podobne pytanie i zgadzam się z dwoma najwyżej ocenionymi odpowiedziami. Próbując to sobie wyjaśnić, stwierdziłem, że jeśli specyfikacje, które idą w parze ze wzorcem repozytorium, są implementowane jako pierwszorzędne elementy modelu domeny, to mogę

  • ponowne wykorzystanie definicji specyfikacji z różnymi parametrami,
  • manipulować istniejącymi parametrami instancji Specyfikacji (np. w celu specjalizacji),
  • połącz je,
  • wykonywać logikę biznesową na nich bez konieczności uzyskiwania dostępu do bazy danych,
  • i oczywiście przetestuj je jednostkowo niezależnie od rzeczywistych implementacji repozytorium.

Mogę nawet posunąć się tak daleko i stwierdzić, że o ile wzorzec Repozytorium nie jest używany razem ze wzorcem Specification, nie jest to tak naprawdę „Repozytorium”, ale DAL. Wymyślony przykład w pseudokodzie:

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

Szczegóły można znaleźć w Esej Specyfikacji Fowlera (na tym oparłem powyższe).

DAL miałby specjalistyczne metody, takie jak

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

Możesz zobaczyć, jak szybko może to stać się uciążliwe, zwłaszcza, że ​​musisz zdefiniować każdy z interfejsów DAL / DAO za pomocą tego podejścia i zaimplementować metodę zapytania DAL.

W .NET zapytania LINQ mogą być jednym ze sposobów implementacji specyfikacji, ale łączenie specyfikacji (wyrażeń) może nie być tak płynne, jak w przypadku rozwiązania stworzonego w domu. Kilka pomysłów na to opisano w tym pytaniu SO .


2

Osobiście uważam, że chodzi o mapowanie, patrz: http://www.martinfowler.com/eaaCatalog/repository.html . Zatem dane wyjściowe / dane wejściowe z repozytorium są obiektami domeny, którymi na DAL może być wszystko. Dla mnie jest to ważny dodatek / ograniczenie, ponieważ możesz dodać implementację repozytorium dla bazy danych / usługi / czegokolwiek z innym układem i masz jasne miejsce, w którym możesz skoncentrować się na wykonywaniu mapowania. Jeśli nie użyjesz tego ograniczenia i masz mapowanie w innym miejscu, to posiadanie różnych sposobów reprezentowania danych może wpłynąć na kod w miejscach, w których nie powinien być zmieniany.


1

Chodzi o interpretację i kontekst. Mogą być bardzo podobne lub nawet bardzo różne, ale dopóki rozwiązanie działa, co kryje się w nazwie!


1

W świecie zewnętrznym (tj. Kod klienta) repozytorium jest takie samo jak DAL, z wyjątkiem:

(1) jego metody insert / update / delete są ograniczone do obiektu kontenera danych jako parametru.

(2) do operacji odczytu może wymagać prostej specyfikacji, takiej jak DAL (na przykład GetByPK) lub specyfikacji zaawansowanej.

Wewnętrznie współpracuje z warstwą mapowania danych (na przykład kontekstem struktury jednostki itp.), Aby wykonać rzeczywistą operację CRUD.

Czego wzorzec repozytorium nie oznacza: -

Widziałem również, że ludzie często byli zdezorientowani, mając oddzielną metodę Save jako przykładową implementację wzorca repozytorium, oprócz metod Insert / Update / Delete, które zatwierdzają wszystkie zmiany w pamięci wykonane przez metody insert / update / delete do bazy danych. Możemy mieć metodę Save na pewno w repozytorium, ale repozytorium nie jest odpowiedzialne za izolowanie w pamięci CUD (Create, Update, Delete) i metod trwałości (które wykonują rzeczywistą operację zapisu / zmiany w bazie danych), ale odpowiedzialność wzorca jednostki pracy.

Mam nadzieję że to pomoże!


1

Repozytorium to wzorzec, to sposób na zaimplementowanie rzeczy w ustandaryzowany sposób w celu ponownego wykorzystania kodu, jak tylko możemy.


1

Zaletą używania wzorca repozytorium jest mockowanie warstwy dostępu do danych, dzięki czemu można przetestować kod warstwy biznesowej bez wywoływania kodu DAL. Są inne duże zalety, ale wydaje mi się to bardzo istotne.


1
Nadal możesz mockować DAL, nie musi to być repozytorium jako takie. Ważną kwestią jest to, że niezależnie od używanej strategii dostępu do danych, powinna implementować interfejs. Umożliwi to korzystanie z kontenerów IoC, a także dokładne testowanie kodu biznesowego bez konieczności przechowywania danych.
cdaq

0

Z tego, co rozumiem, mogą oznaczać w zasadzie to samo - ale nazewnictwo różni się w zależności od kontekstu.

Na przykład, możesz mieć klasę Dal / Dao, która implementuje interfejs IRepository.

Dal / Dao to termin dotyczący warstwy danych; wyższe poziomy aplikacji myślą w kategoriach repozytoriów.


0

Więc w większości (prostych) przypadków DAO jest implementacją Repozytorium?

O ile rozumiem, wydaje się, że DAO zajmuje się właśnie dostępem do bazy danych (CRUD - ale nie ma selekcji ?!), podczas gdy Repozytorium pozwala na abstrakcję całego dostępu do danych, być może będąc fasadą dla wielu DAO (być może różnych źródeł danych).

Czy jestem na dobrej drodze?


Właściwie odwróciłbym to i powiedziałbym, że z uproszczonego punktu widzenia repozytorium to szczególny styl implementacji DAO, ale tak, jesteś na dobrej drodze. (R z CRUD = Read, więc to twój wybór.)
Jeromy Irvine

0

Można argumentować, że „repozytorium” to specyficzna klasa, a „DAL” to cała warstwa składająca się z repozytoriów, DTO, klas narzędzi i wszystkiego, co jest wymagane.

Korzystając z naszej strony potwierdzasz, że przeczytałeś(-aś) i rozumiesz nasze zasady używania plików cookie i zasady ochrony prywatności.
Licensed under cc by-sa 3.0 with attribution required.