2010-10-31 9 views
24

Supponendo problema dominio Stack Overflow e la seguente definizione di eventi:Sourcing eventi e Leggi generazione Modello

UserRegistered(UserId, Name, Email) 
UserNameChanged(UserId, Name) 
QuestionAsked(UserId, QuestionId, Title, Question) 

Supponendo che il seguente stato di vendite evento (in ordine di apparizione):

1) UserRegistered(1, "John", "[email protected]") 
2) UserNameChanged(1, "SuperJohn") 
3) UserNameChanged(1, "John007") 
4) QuestionAsked(1, 1, "Help!", "Please!") 

Supponendo il seguente modello di lettura denormalizzato per l'elenco di domande (per la prima pagina di SO):

QuestionItem(UserId, QuestionId, QuestionTitle, Question, UserName) 

E il seguente gestore di eventi (che si basa il modello di lettura denormalizzato):

public class QuestionEventsHandler 
{ 
    public void Handle(QuestionAsked question) 
    { 
     var item = new QuestionItem(
      question.UserId, 
      question.QuestionId, 
      question.Title, 
      question.Question, 
      ??? /* how should i get name of the user? */); 
     ... 
    } 
} 

La mia domanda è come posso trovare il nome dell'utente che ha chiesto una domanda? O più comune: come devo gestire gli eventi se il mio modello di lettura denormalizzato richiede dati aggiuntivi che non sono presenti nel particolare evento?

Ho esaminato campioni esistenti di CQRS tra cui SimpleSQRS di Greg Young e Fohjin campione di Mark Nijhof. Ma mi sembra che operino solo con dati inclusi negli eventi.

+0

Altro discussione: http://groups.google.com/group/dddcqrs/browse_thread/thread/5ead47db3261dcb5/b069165e48467f41?lnk=gst&q=include+information+in+event#b069165e48467f41 –

risposta

3

Basta arricchire l'evento con tutte le informazioni necessarie.

L'approccio di Greg, come ricordo, arricchisce l'evento durante la creazione e lo memorizza/pubblica in questo modo.

+0

Grazie Rinat! Verrò con il tuo suggerimento, ma sei davvero d'accordo sul fatto che questa sia una buona soluzione per arricchire gli eventi del dominio con i dati che sono necessari solo per il modello di lettura? –

+1

Sì. Non ci sono grossi inconvenienti che io possa vedere. Inoltre, lo storage è economico in questi giorni e gli eventi di dominio arricchiti aiutano ad analizzare il tuo sistema anche in seguito. Per esempio, spesso metto un sacco di statistiche sulle prestazioni in operazioni che stressano IO o CPU; questa informazione non è nemmeno usata nei modelli letti. Ma ho bisogno di ottimizzare le prestazioni Posso interrogare il log di dominio con LINQ per la cronologia delle operazioni e i dettagli esatti delle prestazioni. –

+0

Uno svantaggio sarebbe che non sei necessariamente in grado di cambiare il produttore di eventi. Un altro che l'evento diventerà gonfio di dati incoerenti col passare del tempo e sempre più gestori di eventi che desiderano aggiungere informazioni specifiche al proprio sistema. Quali sono gli svantaggi di consentire al gestore di eventi di interrogare il modello di lettura per le informazioni aggiuntive? –

-1

Estrarre eventi da EventStore.

Ricordare: i modelli di lettura devono disporre già dell'accesso in sola lettura a EventStore. Leggi I modelli sono usa e getta. Sono semplicemente viste memorizzate nella cache. Dovresti essere in grado di eliminare/espirare i tuoi modelli letti in qualsiasi momento e ricostruire automaticamente i tuoi ReadModels da EventStore. Quindi, i tuoi ReadModelBuilder devono già essere in grado di eseguire una query per gli eventi passati.

public class QuestionEventsHandler 
{ 
    public void Handle(QuestionAsked question) 
    { 
     // Get Name of User 
     var nameChangedEvent = eventRepository.GetLastEventByAggregateId<UserNameChanged>(question.UserId); 

     var item = new QuestionItem(
      question.UserId, 
      question.QuestionId, 
      question.Title, 
      question.Question, 

      nameChangedEvent.Name 
    } 
} 

realizzare anche - il repository EventStore non deve essere il vero EventStore, anche se sicuramente potrebbe essere. Il vantaggio dei sistemi distribuiti è la possibilità di replicare facilmente EventStore, se necessario, più vicino ai propri ReadModels.

Ho riscontrato lo stesso identico scenario ... dove avevo bisogno di più dati di quanti ne fossero disponibili in un singolo evento. Ciò è particolarmente vero per gli eventi di tipo Crea che richiedono la compilazione di un nuovo ReadModel con stato iniziale.

Da modelli di lettura: è possibile estrarre da altri modelli di lettura. Ma io davvero non lo consiglio, poiché introdurrebbe una grossa sfera di fango di dipendenza in cui le visualizzazioni dipendono dalle visualizzazioni che dipendono dalle visualizzazioni.

Dati aggiuntivi negli eventi: non vuoi davvero gonfiare i tuoi eventi con tutti i dati extra necessari per le visualizzazioni. Ti farà davvero male quando il tuo dominio cambia & devi migrare gli eventi. Gli eventi di dominio hanno scopi specifici: rappresentano cambiamenti di stato. Non visualizzare i dati.

Spero che questo aiuti -

Ryan

+1

Questo presuppone che tu abbia accesso al repository di eventi, nella mia mente i gestori dovrebbero ricevere solo eventi invece di eventi pull. Funzionerebbe in un sistema altamente distribuito? –

+0

"I tuoi modelli letti devono avere accesso in sola lettura a EventStore". Questa è una novità per me. Non vedo alcun motivo per cui il lato di lettura debba avere accesso all'archivio degli eventi. Ha semplicemente bisogno di essere avvisato quando si verifica un evento. Personalmente non ho problemi a interrogare il nome utente dal lato di lettura, dato che il gestore esiste comunque sul lato di lettura. –

+0

Nel nostro progetto attuale avremo molto probabilmente accesso in lettura all'archivio degli eventi, perché un flusso di eventi relativi a un particolare aggregato deve essere visualizzato nell'interfaccia utente, lo stile della timeline di Facebook. Sì, potremmo usare una proiezione e generarla (e forse lo faremo se questo ha bisogno di una denormalizzazione), ma per ora stiamo cercando di interrogare il modo più diretto. – Dav

17

Personalmente penso che ci sia nulla di sbagliato nel cercare il nome dell'utente all'interno del gestore di eventi.Ma se si è in una posizione in cui non è possibile interrogare il nome dal modello di lettura dell'utente, introdurrei un gestore di eventi aggiuntivo a QuestionEventsHandler, per gestire l'evento UserRegistered.

In questo modo QuestionEventsHandler è in grado di conservare il proprio repository di nomi utente (non è necessario memorizzare l'e-mail dell'utente). Il gestore QuestionAsked può quindi interrogare il nome dell'utente direttamente dal proprio repository (come Rinat Abdullin ha detto che lo storage è economico!).

Inoltre, poiché il modello di lettura di QuestionItem contiene il nome dell'utente, è necessario gestire anche l'evento UserNameChanged all'interno di QuestionEventsHandler per garantire che il campo del nome all'interno di QuestionItem sia aggiornato.

Per me questo sembra meno sforzo di 'arricchire gli eventi' e ha il vantaggio di non dipendenze di costruzione su altre parti del sistema e dei loro modelli letti.

+0

Si può finire per avere un sacco di dati duplicati ovunque nel modello letto, se non si presta attenzione – Narvalex

+0

Vero, ma il modello letto è spesso denormalizzato e quindi avrà sempre dati duplicati. –