Garantire la coerenza transazionale con DDD

9

Sto iniziando con DDD e capisco che le radici aggregate sono utilizzate per assicurare la coerenza transnazionale. Non dovremmo modificare più aggregati in un servizio applicativo.

Vorrei sapere comunque come affrontare la seguente situazione.

Ho una radice aggregata chiamata Prodotti.

Esiste anche una radice aggregata chiamata Gruppo.

Entrambi hanno Id e possono essere modificati indipendentemente.

Più prodotti possono puntare allo stesso gruppo.

Ho un servizio di applicazione che può modificare il gruppo di un prodotto:

ProductService.ChangeProductGroup(string productId, string groupId)

  1. Controlla il gruppo esiste
  2. Ottieni prodotto dal repository
  3. Imposta il suo gruppo
  4. Scrivi il prodotto nel repository

Ho anche un servizio applicativo in cui il gruppo può essere cancellato:

GroupService.DeleteGroup(string groupId)  1. Ottieni prodotti dal repository il cui groupId è impostato su groupId, assicurati che il conteggio sia 0 o che venga interrotto  2. Elimina gruppo dal repository di gruppi  3. Salva le modifiche

La mia domanda è il seguente scenario, cosa accadrebbe se:

Nel ProductService.ChangeProductGroup, controlliamo che il gruppo esista (lo fa), quindi subito dopo verifica che un utente separato cancelli il productGroup (tramite l'altro GroupService.DeleteGroup). In questo caso impostiamo un riferimento a un prodotto che è stato appena cancellato?

Questo è un difetto nel mio design in quanto dovrei usare un design di dominio diverso (aggiungendo ulteriori elementi se necessario), o dovrei usare le transazioni?

    
posta g18c 16.11.2013 - 18:16
fonte

3 risposte

2

Abbiamo lo stesso problema.

E non ho modo di risolvere questo problema, ma con le transazioni o con il controllo della coerenza nel DB per ottenere un'eccezione nel caso peggiore.

Puoi anche utilizzare il blocco pessimistico, il blocco della radice aggregata o solo le sue parti per altri client fino al completamento della transazione commerciale, che è in qualche misura equivalente alla transazione serializzabile.

Il modo in cui si procede pesantemente dipende dal sistema e dalla logica aziendale.
La concorrenza non è affatto un compito facile.
Anche se riesci a individuare un problema, come lo risolveresti? Basta annullare l'operazione o consentire all'utente di "unire" le modifiche?

Utilizziamo Entity Framework e EF6 utilizza read_commited_snapshot per impostazione predefinita, quindi due letture consecutive dal repository possono darci dati incoerenti. Teniamo questo a mente per il futuro quando i processi aziendali saranno più chiaramente delineati e possiamo prendere una decisione infromediata. E sì, controlliamo ancora la coerenza a livello di modello come fai tu. Ciò consente almeno di testare BL separatamente dal DB.

Ti suggerisco anche di riflettere su coerenza del repository nel caso in cui si abbiano transazioni commerciali" lunghe ". È piuttosto difficile come si è scoperto.

    
risposta data 19.11.2013 - 22:54
fonte
1

Penso che questa non sia una domanda specifica per il Domain-Driven Design, ma una per la gestione delle risorse.

Le risorse devono essere semplicemente bloccate così come sono acquisite .

Questo è vero quando il servizio applicativo sa in anticipo che la risorsa acquisita (il Group aggregato, nel tuo esempio) sta per essere modificata. In Domain-Driven Design, il blocco delle risorse è un aspetto che appartiene al repository.

    
risposta data 30.01.2014 - 00:09
fonte
0

Perché non memorizzi gli ID prodotto nell'entità Gruppo? In questo modo hai a che fare solo con un singolo aggregato che faciliterà le cose.

Dovrai quindi implementare un tipo di modello di concorrenza, ad es. Se si sceglie la concorrenza ottimistica, aggiungere semplicemente una proprietà di versione all'entità Gruppo e generare un'eccezione se le versioni non corrispondono durante l'aggiornamento di i.e.

Aggiungi prodotto a un gruppo

  1. Verifica se il prodotto esiste
  2. Recupera gruppo dal repository (inclusa la relativa proprietà id versione)
  3. Group.Add (ProductId)
  4. Salva gruppo utilizzando il repository (aggiorna con il nuovo id versione e aggiungi una clausola where per garantire che la versione non sia cambiata.)

Molti ORM hanno una concorrenza ottimistica basata sull'uso degli ID di versione o dei timestamp, ma è facile far girare il tuo. Ecco un buon post su come è stato fatto in href="http://ayende.com/blog/3946/nhibernate-mapping-concurrency"> link .

    
risposta data 29.01.2014 - 23:16
fonte

Leggi altre domande sui tag