Pułapki projektowania opartego na domenach dzięki Entity Framework

12

Wiele tutoriali na temat DDD, które studiowałem, dotyczy głównie teorii. Wszystkie mają podstawowe przykłady kodu (Pluralsight i podobne).

W Internecie próbuje się również kilka osób, aby stworzyć samouczki dotyczące DDD z EF. Jeśli zaczniesz je studiować krótko - szybko zauważysz, że bardzo się od siebie różnią. Niektóre osoby zalecają, aby aplikacja była minimalna i unikała wprowadzania dodatkowych warstw, np. Repozytorium nad EF , inne zdecydowanie generują dodatkowe warstwy, często nawet naruszając SRP poprzez wstrzykiwanie DbContextdo Aggregate Roots.

Okropnie przepraszam, jeśli zadaję pytanie oparte na opiniach, ale ...

Jeśli chodzi o praktykę - Entity Framework jest jednym z najpotężniejszych i najczęściej używanych ORM. Niestety nie znajdziesz w nim kompleksowego kursu obejmującego DDD.


Ważne aspekty:

  • Entity Framework DbSetwyciąga UoW & Repository ( ) z pudełka

  • z EF twoje modele mają właściwości nawigacyjne

  • EF wszystkie modele są zawsze dostępne off DbContext(są one reprezentowane jako DbSet)

Pułapki:

  • nie możesz zagwarantować, że wpływ na twoje modele potomne będzie mieć tylko Zagregowane Korzenie - twoje modele mają właściwości nawigacyjne i można je modyfikować i wywoływaćdbContext.SaveChanges()

  • dzięki DbContextczemu możesz uzyskać dostęp do każdego modelu, omijając w ten sposób Korzeń zagregowany

  • można ograniczyć dostęp dzieci głównego obiektu za pośrednictwem ModelBuilderw OnModelCreatingsposób oznaczając je jako pola - I nadal nie wierzę, że to właściwa droga o DDD plus to trudno ocenić, jaki rodzaj przygody może to doprowadzić w przyszłości ( dość sceptyczny )

Konflikty:

  • bez implementacji kolejnej warstwy repozytorium, która zwraca Agregat, nie jesteśmy nawet w stanie częściowo rozwiązać wyżej wspomnianych pułapek

  • wdrażając dodatkową warstwę repozytorium, ignorujemy wbudowane funkcje EF (każde DbSetjest już repozytorium) i nadmiernie komplikujemy aplikację


Mój wniosek:

Proszę o wybaczenie mojej ignorancji, ale w oparciu o powyższe informacje - albo Entity Framework nie jest odpowiedni do projektowania opartego na domenie, albo projektowanie oparte na domenie jest niedoskonałe i przestarzałe .

Podejrzewam, że każde z tych podejść ma swoje zalety, ale teraz jestem całkowicie zagubiony i nie mam najmniejszego pojęcia, jak pogodzić EF z DDD.


Jeśli się mylę - czy ktoś mógłby szczegółowo opisać prosty zestaw instrukcji (lub nawet podać porządny przykład kodu), jak postępować w sprawie DDD z EF, proszę?

Alex Herman
źródło
Wyszczególniłem tutaj kroki zgodnie z moim rozumieniem działania EF. Mimo to te kroki nie rozwiązują problemu z dostępem dzieci do systemu nawigacyjnego. właściwości lub przez DbSets wyłącza DbContext.
Alex Herman

Odpowiedzi:

8

DDD i EF nie mają ze sobą nic wspólnego.

DDD to koncepcja modelowania. Oznacza to przemyślenie Domeny, wymagań biznesowych i modelowanie ich. Zwłaszcza w kontekście orientacji obiektowej oznacza to stworzenie projektu odzwierciedlającego funkcje i możliwości biznesowe.

EF jest technologią trwałości. Dotyczy to głównie danych i rekordów bazy danych.

Ci dwaj są bardzo rozwiedzeni. Projekt DDD może wykorzystywać EF w jakiejś formie pod maską, ale te dwa nie powinny oddziaływać w żaden inny sposób.

Niektóre interpretacje projektowania opartego na domenach faktycznie popierają modelowanie danych i myślę, że o to właśnie chodzi w tym pytaniu. W tej interpretacji „jednostki” i „obiekty wartości” są zasadniczo tylko pozbawionymi funkcji posiadaczami danych, a projekt dotyczy samych właściwości, jakie one posiadają i jakie mają między sobą relacje. W tym kontekście mogą pojawić się DDD vs. EF.

Ta interpretacja jest jednak błędna i zdecydowanie zalecałbym jej całkowite zignorowanie.

Podsumowując : DDD i EF nie wykluczają się wzajemnie, w rzeczywistości są dla siebie nieistotne, o ile wykonujesz właściwe modelowanie obiektów, a nie modelowanie danych. Obiekty DDD nie powinny mieć żadnego kształtu ani formy jako artefakty EF. Podmioty DDD nie powinny być na przykład „podmiotami” EF. Wewnątrz niektórych funkcji związanych z biznesem projekt DDD może wykorzystywać EF z niektórymi powiązanymi obiektami danych, ale powinny one zawsze być ukryte pod odpowiednim dla biznesu interfejsem zorientowanym na zachowanie.

Robert Bräutigam
źródło
1
EF to tylko oszczędność czasu. Śledzenie zmian i trwałość agregatów to miejsce, w którym EF już bardzo pomaga. Niestety obecnie nie ma możliwości zdefiniowania kształtu agregatów na poziomie konfiguracji.
Pavel Voronin,
6

Traktuj EF za to, co to jest, tj. Biblioteka dostępu do danych, która jest tylko nieco mocniej napisana niż surowy ADO.NET. Nie zalecałbym modelowania domeny za pomocą klas encji EF, tak jak nie zalecałbym modelowania domeny za pomocą surowego DataSet lub DataTable.

Rozumiem, że EF jest sprzedawany jako skrót między dostępem do bazy danych a modelowaniem domen, jednak takie podejście jest wewnętrznie wadliwe, ponieważ rozwiązuje dwa zasadniczo niezwiązane ze sobą problemy. W .NET były inne próby zmuszenia klasy do wykonania pewnych całkowicie niezwiązanych rzeczy (np. .NET Remoting) i nie zakończyły się dobrze.

Wykonaj DDD za pomocą klas POCO i nie pozwól, aby schemat bazy danych sterował twoim projektem. Trzymaj EF w warstwie repozytorium / trwałości i nie pozwól, aby jednostki EF wyciekły na zewnątrz.

KolA
źródło
5

Entity Framework wyciąga UoW & Repository (DbSet) z pudełka

Nie.

Abstrakcje Entity Framework zostały zbudowane z myślą o ORM, a nie DDD. DbSetAbstrakcji w dowolnej wersji Entity Framework jest dalekie prostotą DDD Repository - nie wspominając DbContextco naraża zillion rzeczy bardziej niż UnitOfWork.

Oto niewyczerpująca lista elementów w streszczeniu EF Core 2.1 DbSet<TEntity>, których nie potrzebujemy w DDD:

  • Attach(TEntity) i całe jego rodzeństwo
  • Find(Object[])
  • Update(TEntity) i całe jego rodzeństwo
  • Realizowanie IQueryable

Oprócz przeciągania wraz z nimi niepotrzebnych zależności, przesłaniają one zamiar repozytorium, które normalnie ujawnia bardzo proste zachowanie kolekcji. Ponadto nieszczelne abstrakty są ciągłą pokusą dla programistów, aby zbyt mocno związać się z EF i stanowić zagrożenie dla separacji obaw.

Podsumowując: musisz zawinąć te tłuszcze w ładne, usprawnione koncepcje i zgadnij, co to oznacza wprowadzenie dodatkowych klas.

Względnie dobry przykład tego, co można zrobić z EF i DDD (chociaż niektóre wyrażone punkty widzenia są dyskusyjne): https://kalele.io/blog-posts/modeling-aggregates-with-ddd-and-entity-framework/

inne zdecydowanie generują dodatkowe warstwy, często nawet naruszając SRP, wstrzykując DbContext do agregatów Roots

Naprawdę nie widzę związku między dwiema częściami tego zdania. Bez względu na podejście, w DDD jest coś o nazwie Usługa aplikacji i tam manipulujesz Jednostką Pracy / Repozytorium (lub DbContext). Nie w zagregowanych korzeniach.

Chociaż byłoby to uzasadnione podejście, gdyby było wykształconym kompromisem, niedawny trend antyrepozytorium „minimalizm Entity Framework” jest urojeniowy. Obwinia wzorce DDD za tarcie występujące w Entity Framework, gdy tak naprawdę twórcy EF nie zrobili nic, aby ich szkielet był zgodny z najlepszymi praktykami od samego początku. Przez cały czas są one ściśle powiązane z tą samą strukturą, ze wszystkimi problemami związanymi z bezpieczeństwem kodu i łatwością konserwacji, które mogą wystąpić.

guillaume31
źródło
2

Konflikty:

bez implementacji kolejnej warstwy repozytorium, która zwraca Agregat, nie jesteśmy w stanie nawet> częściowo rozwiązać wyżej wspomnianych pułapek

wdrażając dodatkową warstwę repozytorium, ignorujemy wbudowane funkcje EF (każdy DbSet jest już repo) i nadmiernie komplikujemy aplikację

Zastosowałem podejście, w którym każde agregat otrzymuje swój własny DBContext, odwzorowując tylko to, co jest potrzebne do agregacji. Myślę, że opisała to także Julie Lerman.

To zadziałało bardzo dobrze, ale może nie wystarczyć dla bardziej interesujących modeli, w których nie chcesz łączyć swoich koncepcji ze swoimi bytami.

mvg
źródło
Widziałem to wideo również dddcommunity.org/ddd-contributors/...
Alex Herman
Czy są jakieś zalety podejścia DBContext Per Aggregate? Czy to domyślny sposób implementacji DDD z EF?
Alex Herman
Czy Julie Lerman nie miała na myśli DbContext w kontekście Bounded?
Mvision,
0

Chciałbym tylko podzielić się możliwym rozwiązaniem do rozważenia:

  1. unikaj bezpośredniego odwoływania się do projektu EF w warstwie usług

  2. utwórz dodatkową warstwę repozytorium (używa projektu EF i zwraca Korzeń agregacji)

  3. odwołać się do projektu Repository Layer in Service Layer

Architektura :

  • Interfejs użytkownika

  • Warstwa kontrolera

  • Warstwa serwisowa

  • Warstwa repozytorium

  • Entity Framework

  • Projekt podstawowy (zawiera modele EF)


Pułapki, które widzę przy takim podejściu:

  • jeśli repozytorium zwraca korzeń agregujący nie jako drzewo modelu EF (np. zwracamy zmapowany obiekt) - tracimy zdolność EF do śledzenia zmian

  • jeśli Aggregate Root jest modelem EF - wszystkie jego właściwości nawigacyjne są nadal dostępne , nawet jeśli nie możemy sobie z tym poradzić DbContext(nie odwołujemy się do projektu EF w Warstwie usług)

Alex Herman
źródło