Insidie ​​del Domain Driven Design con Entity Framework


12

Molti tutorial su DDD che ho studiato riguardano principalmente la teoria. Tutti hanno esempi di codice rudimentale (Pluralsight e simili).

Sul web ci sono anche tentativi da parte di alcune persone di creare tutorial che trattano DDD con EF. Se inizi a studiarli solo brevemente, noti rapidamente che differiscono molto l'uno dall'altro. Alcune persone raccomandano di ridurre al minimo l'app ed evitare di introdurre livelli aggiuntivi, ad esempio un repository in cima a EF , altri stanno decisamente generando livelli extra, spesso anche violando SRP iniettando DbContextin Radici aggregate.

Mi sto scusando terribilmente se sto facendo una domanda basata sull'opinione, ma ...

Quando si tratta di pratica, Entity Framework è uno degli ORM più potenti e ampiamente utilizzati. Sfortunatamente, non troverai un corso completo su DDD.


Aspetti importanti:

  • Entity Framework porta UoW & Repository ( DbSet) fuori dalla scatola

  • con EF i tuoi modelli hanno proprietà di navigazione

  • con EF tutti i modelli sono sempre disponibili off DbContext(sono rappresentati come a DbSet)

insidie:

  • non puoi garantire che i tuoi modelli figlio siano interessati solo tramite Aggregate Root: i tuoi modelli hanno proprietà di navigazione ed è possibile modificarli e chiamaredbContext.SaveChanges()

  • con DbContextte puoi accedere ad ogni tuo modello, aggirando così la radice aggregata

  • è possibile limitare l'accesso ai figli dell'oggetto root tramite ModelBuilderin OnModelCreatingmetodo contrassegnandoli come campi - io ancora non credere che sia il modo giusto per andare su di DDD, più è difficile valutare quale tipo di avventure questo può portare al futuro ( abbastanza scettico )

conflitti:

  • senza implementare un altro livello di repository che restituisce Aggregate non possiamo nemmeno parzialmente risolvere le insidie ​​sopra menzionate

  • implementando un ulteriore livello di repository ignoriamo le funzionalità integrate di EF (ogni cosa DbSetè già un repository) e complichiamo eccessivamente l'app


La mia conclusione:

Per favore, scusate la mia ignoranza, ma in base alle informazioni di cui sopra: Entity Framework non è adeguato per il Domain-Driven Design o il Domain-Driven Design è un approccio imperfetto e obsoleto .

Sospetto che ciascuno degli approcci abbia i suoi meriti, ma ora sono completamente perso e non ho la minima idea di come conciliare EF e DDD.


Se sbaglio - qualcuno potrebbe almeno dettagliare un semplice set di istruzioni (o anche fornire esempi di codice decente) su come procedere con DDD con EF, per favore?


Ho dettagliato i passaggi qui in base alla mia comprensione di come funziona EF. Tuttavia, questi passaggi non gestiscono il problema di accesso ai bambini tramite nav. proprietà o da DbSet off DbContext.
Alex Herman,

Risposte:


8

DDD ed EF hanno poco a che fare l'uno con l'altro.

DDD è un concetto di modellazione. Significa pensare al dominio, ai requisiti aziendali e modellarli. Soprattutto nel contesto dell'orientamento agli oggetti, significa creare un design che rispecchi le funzioni e le capacità aziendali.

EF è una tecnologia di persistenza. Si occupa principalmente di dati e record di database.

Questi due sono nettamente divorziati. Un progetto DDD può usare EF in qualche forma sotto il cofano, ma i due non dovrebbero interagire in nessun altro modo.

Alcune interpretazioni del Domain-Driven Design sostengono in realtà la modellizzazione dei dati, e penso che sia questa la domanda. In questa interpretazione "Entità" e "Oggetti valore" sono essenzialmente titolari di dati privi di funzioni, e il design si preoccupa delle proprietà che queste possiedono e della relazione che hanno tra loro. In questo contesto potrebbero comparire DDD vs. EF.

Questa interpretazione è tuttavia imperfetta e consiglio vivamente di ignorarla del tutto.

In conclusione : DDD ed EF non si escludono a vicenda, in realtà sono reciprocamente irrilevanti, purché si stia eseguendo la modellazione di oggetti e non la modellazione di dati. Gli oggetti DDD non devono essere in nessuna forma o forma artefatti EF. Le entità DDD non dovrebbero essere ad esempio "entità" EF. All'interno di alcune funzioni rilevanti per l'azienda, un progetto DDD potrebbe utilizzare EF con alcuni oggetti dati correlati, ma questi dovrebbero essere sempre nascosti sotto un'interfaccia orientata al comportamento rilevante per l'azienda.


1
EF è solo un risparmio di tempo. Il rilevamento delle modifiche e la persistenza degli aggregati è il punto in cui EF aiuta già molto. Sfortunatamente, al momento non è possibile definire la forma degli aggregati a livello di configurazione.
Pavel Voronin,

6

Tratta EF per quello che è cioè la libreria di accesso ai dati che è solo leggermente più fortemente tipizzata di ADO.NET non elaborata. Non consiglierei di modellare il tuo dominio utilizzando le classi di entità EF proprio come non consiglierei di modellare il dominio utilizzando DataSet o DataTable non elaborati.

Comprendo che EF viene venduto come scorciatoia tra l'accesso al database e la modellazione del dominio, tuttavia questo approccio è intrinsecamente imperfetto in quanto risolve due problemi in gran parte non correlati. Ci sono stati altri tentativi in ​​.NET di fare in modo che una classe eseguisse cose completamente non correlate (ad es. .NET Remoting) e non sono finite bene.

Esegui il DDD usando le classi POCO e non lasciare che lo schema del database guidi la tua progettazione. Mantieni EF all'interno del repository / livello di persistenza e non lasciare che le entità EF perdano all'esterno.


5

Entity Framework porta UoW & Repository (DbSet) fuori dalla scatola

No.

Le astrazioni di Entity Framework sono state costruite tenendo presente ORM, non DDD. L' DbSetastrazione in qualsiasi versione di Entity Framework non è affatto vicina alla semplicità di un repository DDD - per non parlare del fatto DbContextche espone un miliardo di cose in più di un UnitOfWork.

Ecco un elenco non esaustivo di elementi nell'abstract di EF Core 2.1 di DbSet<TEntity>cui non abbiamo bisogno in DDD:

  • Attach(TEntity) e tutti i suoi fratelli
  • Find(Object[])
  • Update(TEntity) e tutti i suoi fratelli
  • Implementazione IQueryable

Oltre a trascinare con loro dipendenze non necessarie, queste oscurano l'intento di un repository che normalmente espone un comportamento di raccolta molto semplice. Inoltre le astrazioni che perdono sono una costante tentazione per gli sviluppatori di accoppiarsi troppo a EF e una minaccia alla separazione delle preoccupazioni.

Concludendo: è necessario avvolgere questi fatti in concetti piacevoli e ottimizzati e indovinare cosa, ciò significa introdurre classi extra.

Un esempio relativamente valido di cosa puoi fare con EF e DDD (anche se alcuni punti di vista espressi sono discutibili): https://kalele.io/blog-posts/modeling-aggregates-with-ddd-and-entity-framework/

altri stanno generando decisamente livelli extra, spesso anche violando SRP iniettando DbContext in aggregati

Non vedo davvero la connessione tra le due parti di questa frase. Indipendentemente dall'approccio, in DDD c'è qualcosa che si chiama Application Service ed è qui che manipoli l'Unità di lavoro / Repository (o DbContext). Non nelle radici aggregate.

Mentre potrebbe essere un approccio valido se fosse un compromesso colto, la recente tendenza anti-repository, "Entity Framework minimalism" è delirante. Incolpa i modelli DDD per l'attrito che si verifica con Entity Framework quando in realtà sono i creatori di EF che non hanno fatto nulla per rendere il loro framework conforme alle migliori pratiche. Nel frattempo si stanno accoppiando strettamente a quello stesso framework con tutti i problemi in termini di sicurezza del codice e manutenibilità che possono derivarne.


2

conflitti:

senza implementare un altro livello di repository che restituisce Aggregate non possiamo nemmeno> parzialmente risolvere le insidie ​​di cui sopra

implementando un ulteriore livello di repository stiamo ignorando le funzionalità integrate di EF (ogni DbSet è già un repository) e complichiamo eccessivamente l'app

Ho usato un approccio in cui ogni aggregato ottiene il proprio DBContext, mappando solo ciò che è necessario per l'aggregato. Penso che questo sia stato descritto anche da Julie Lerman.

Ciò ha funzionato molto bene, ma potrebbe non essere sufficiente per modelli più interessanti, in cui non si desidera collegare i concetti alle entità.



Ci sono dei vantaggi nell'approccio DBContext per aggregato? È questo il modo predefinito per implementare DDD con EF?
Alex Herman,

Julie Lerman non significava DbContext per contesto limitato?
Mvision

0

Vorrei solo condividere la possibile soluzione da considerare:

  1. evitare di fare riferimento direttamente al progetto EF nel livello di servizio

  2. creare un livello repository aggiuntivo (utilizza il progetto EF e restituisce la radice aggregata)

  3. fare riferimento al progetto Layer repository nel livello di servizio

Architettura :

  • UI

  • Livello controller

  • Livello di servizio

  • Strato di deposito

  • Entity Framework

  • Progetto principale (contiene modelli EF)


Le insidie ​​che vedo con questo approccio:

  • se un repository restituisce la radice aggregata non come albero modello EF (ad es. restituiamo un oggetto mappato), stiamo perdendo la capacità di EF di tracciare le modifiche

  • se la radice aggregata è un modello EF - tutte le sue proprietà di navigazione sono ancora disponibili , anche se non possiamo gestirle DbContext(non facciamo riferimento al progetto EF nel livello di servizio)

Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.