English 中文(简体)
Event Sourcing and Read Model generation
原标题:

Assuming Stack Overflow domain problem and the following definition of events:

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

Assuming the following state of event store (in the order of appearance):

1) UserRegistered(1, "John", "john@gmail.com")
2) UserNameChanged(1, "SuperJohn")
3) UserNameChanged(1, "John007")
4) QuestionAsked(1, 1, "Help!", "Please!")

Assuming the following denormalized read model for questions listing (for the first page of SO):

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

And the following event handler (which builds denormalized read model):

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? */);
        ...
    }
}

My question is how can i find the name of the user who asked a question? Or more common: how should i handle events if my denormalized read model requires additional data which is not exists in the particular event?

I ve examined existing samples of CQRS including SimpleSQRS of Greg Young and Fohjin sample of Mark Nijhof. But it seems to me that they are operate only with data that is included in events.

最佳回答

Just enrich the event with all the necessary information.

Greg s approach, as I recall, - enrich the event while creating and store/publish it this way.

问题回答

Personally I think there s nothing wrong with looking up the user s name from within the event handler. But if you re in a position where you can t query the name from the User s read model then I d introduce an additional event handler to QuestionEventsHandler, to handle the UserRegistered event.

That way the QuestionEventsHandler could maintain its own repository of user names (you wouldn t need to store the users email). The QuestionAsked handler can then query the user s name direct from it s own repository (as Rinat Abdullin said storage is cheap!).

Besides since your QuestionItem read model holds the user s name, you would need to handle the UserNameChanged event within the QuestionEventsHandler as well to ensure the name field within the QuestionItem is up-to-date.

To me this seems less effort than enriching the events and has the benefit of not building dependencies on other parts of the system and their read models.

Pull events from the EventStore.

Remember - Your read models need to have read-only access to the EventStore already. Read Models are disposable. They are simply cached views. You should be able to delete / expire your Read Models at any time - and automatically rebuild your ReadModels from the EventStore. So - your ReadModelBuilders must already be able to query for past events.

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
    }
}

Also realize - the EventStore repository need not be the true EventStore, although it certainly could be. The advantage of distributed systems is that you can easily replicate the EventStore, if you needed, closer to your ReadModels.

I encountered this exact same scenario... where I needed more data than was available in a single event. This is especially true for Create-type events which require populating a new ReadModel with initial state.

From Read Models: You could pull from other Read Models. But I really don t recommend this, as you would introduce a big ball of dependency mud where views depend on views depend on views.

Additional Data in Events: You really don t want to bloat your events with all the extra data you ll need for views. It will really hurt you when your domain changes & you need to migrate events. Domain Events have specific purposes - they represent state changes. Not view data.

Hope this helps -

Ryan





相关问题
DDD - Returning entity in response to a service operation

I am new to domain driven development & have a simple question. If a service needs to generate some entity as a response to an operation then how should it be done? One of the ways is to inject ...

Domain Driven Design efforts in dynamic languages? [closed]

Are you aware of any DDD efforts in a dynamic language ? Practical resources on DDD tend to decrease quite dramatically when straying from enterprise-oriented solutions (a google search exluding C#, ....

Accessing domain objects in the view

If I don t want to expose the internal state of my Domain Objects, but I need to display them, I can think of three approaches. Which of these is the most "correct" (if any?). The "DTO/ViewModel ...

DDD screen cast question?

I wathced a screen cast on DDD by Greg Young the other day which spoke about persisting all state transitions of an object, instead of it s state when saved, then to load it "replay" all these ...

How to fluent-map this (using fluent nhibernate)?

I have two tables in my database "Styles" and "BannedStyles". They have a reference via the ItemNo. Now styles can be banned per store. So if style x is banned at store Y then its very possible that ...

热门标签