2012-06-30 16 views
11

Sto costruendo un'applicazione con un modello di dominio utilizzando CQRS e concetti di eventi di dominio (ma nessun evento di approvvigionamento, solo semplice vecchio SQL). Non c'è stato nessun problema con gli eventi di tipo SomethingChanged. Poi sono rimasto bloccato nell'implementare eventi SomethingCreated.Nuovo ID entità nell'evento di dominio

Quando creo una qualche entità, che è associata a una tabella con chiave primaria identità poi non si conosce l'ID fino a che viene mantenuto l'entità. L'entità è ignoranza della persistenza, quindi quando pubblichi un evento dall'interno dell'entità, Id non è noto - è magicamente impostato solo dopo aver chiamato context.SaveChanges(). Quindi come/dove/quando posso inserire l'ID nei dati dell'evento?

pensavo:

  • Compreso il riferimento all'entità nell'evento. Ciò funzionerebbe all'interno del dominio ma non necessariamente in un ambiente distribuito con più sistemi autonomi che comunicano per eventi/messaggi.
  • Sovrascrivere SaveChanges() per aggiornare in qualche modo gli eventi accodati per la pubblicazione. Ma gli eventi devono essere immutabili, quindi questo sembra molto sporco.
  • Eliminazione dei campi identità e utilizzo dei GUID generati nel costruttore entità. Questo potrebbe essere il più semplice, ma potrebbe colpire le prestazioni e rendere più difficili altre cose, come il debug o l'interrogazione (where id = 'B85E62C3-DC56-40C0-852A-49F759AC68FB', n. MIN, MAX ecc.). Questo è quello che vedo in molte applicazioni di esempio.
  • Approccio ibrido: non utilizzare l'identità e utilizzarla principalmente per chiavi esterne e join più veloci, ma utilizzare GUID come identificativo univoco mediante il quale estrarre le entità dal repository nell'applicazione.
+3

Non includere un riferimento all'entità nell'evento. Va bene attaccare l'id dopo il salvataggio. Dovrebbe essere considerato immutabile dopo la pubblicazione. Tuttavia questo potrebbe finire per essere problematico se hai intenzione di consentire tentativi nel contesto di produzione dell'evento.C'è un valore nell'assegnazione degli ID dall'esterno, così tanto che penso che questa dovrebbe essere una strategia predefinita. Quindi, utilizzare entrambi i GUID e l'approccio ibrido potrebbe funzionare. Un altro approccio potrebbe essere un meccanismo HILO o qualcosa come il fiocco di neve. –

+0

Potresti elaborare su HILO e fiocco di neve? – Pein

+0

http://nhforge.org/blogs/nhibernate/archive/2009/03/20/nhibernate-poid-generators-revealed.aspx e http://engineering.twitter.com/2010/06/announcing-snowflake.html –

risposta

9

Personalmente mi piacciono i GUID per identificatori univoci, specialmente in ambienti distribuiti multiutente, dove gli ID numerici causano problemi. Pertanto, non utilizzo mai colonne/proprietà di identità generate dal database e questo problema scompare.

mancanza di ciò, dato che si sta seguendo CQRS, si hanno indubbiamente un CreateSomethingCommand e corrispondente CreateSomethingCommandHandler che esegue effettivamente i punti necessari per creare la nuova istanza e persistono il nuovo oggetto utilizzando il repository (tramite context.SaveChanges). Alzerò qui l'evento SomethingCreated piuttosto che nell'oggetto dominio stesso.

Per uno, questo risolve il problema, perché il gestore di comandi può attendere che l'operazione di database per completare, tirare fuori il valore di identità, aggiornare l'oggetto poi passare l'identità alla manifestazione. Ma, cosa più importante, affronta anche la difficile domanda su esattamente quando l'oggetto 'creato'?

Crescere un evento dominio nel costruttore è cattiva pratica come costruttori dovrebbero essere magra e semplicemente eseguire l'inizializzazione. Inoltre, nel tuo modello, l'oggetto non viene realmente creato finché non viene assegnato un ID. Ciò significa che sono necessari ulteriori passaggi di inizializzazione dopo l'esecuzione del costruttore. Se hai più di un passo, fai rispettare l'ordine di esecuzione (un altro anti-pattern) o metti un segno di spunta in ognuno per riconoscere quando sono tutti fatti (ooh, puzzolenti)? Spero che tu possa vedere come questo può rapidamente sfuggire di mano.

Quindi, la mia raccomandazione è di sollevare l'evento dal gestore di comandi. (Nota: anche se si passa a identificatori GUID, mi piacerebbe seguire questo approccio, perché non si dovrebbe mai alzare gli eventi da costruttori.)

+5

"Quindi, il mio consiglio è di aumentare l'evento dal gestore di comando" => Gli eventi dovrebbero prendere parte al modello di dominio. Invece di un povero costruttore, per aumentare il significato, creerei una fabbrica statica: 'create' sollevando l'evento in caso di successo. – Mik378

+0

"Per uno, questo risolve il tuo problema perché il gestore di comandi può attendere il completamento dell'operazione del database, estrarre il valore dell'identità" - cosa succede se il timeout si presenta in qualche modo: l'oggetto viene creato, ma il gestore di comandi genera un'eccezione? Per semplicità, vorrei implementare il gestore di comandi come UoW. In tal caso, è necessario utilizzare Guid come id di entità anziché id di entità come campo del database di identità. –