CQRS Read Model Design when Event Sourcing with a Parent-Child-GrandChild… relationship

前端 未结 2 915
隐瞒了意图╮
隐瞒了意图╮ 2021-02-20 02:15

I\'m in the process of writing my first CQRS application, let\'s say my system dispatches the following commands:

  • CreateContingent (Id, Name)
  • CreateTeam (
相关标签:
2条回答
  • 2021-02-20 02:47

    What you're probably going to end up with is a combination of 1 and 2. There is absolutely no problem with enhancing or enriching events to have more information in them. It is actually quite helpful.

    • What if a future subscriber to the event needs even more info? I can't add it!

    You can add it to the events going forward. If you need historical data you'll have to find it somewhere else. You can't build events with all the data in the world on them just on the off chance that you'll need it in the future. It is even allowable to go back and add more data to your historical events. Some people would frown on this as rewriting history but you're not, you're simply enhancing history. As long as you don't change the existing data you should be fine.

    I suspect that your event handlers are also going to need to subscribe to more events as time continues. For instance are teams going to need to be renamed? If so then you'll need to handle that event. Don't be afraid to have multiple copies of the same data in different read views. Coming from a relational database background this duplication of data is one of the hardest things to get use to.

    In the end be pragmatic. If you're encountering pain in applying CQRS then change how you're applying it.

    0 讨论(0)
  • 2021-02-20 03:02

    Another option that comes to my mind is:

    In your read side, you first build normalized views by events from the write side.

    E.g.:

    contingents table:
    -----------
    id, name
    
    teams table:
    -----------
    id, name
    
    contigents_teams table:
    -----------
    contigent_id, team_id
    

    On ContingentCreated event, you just insert the record into the contingents table.

    On TeamCreated event, you just insert the record into the teams table.

    On TeamAssignToContingent event, you insert the record into the contigents_teams table.

    On TeamNameChanged event, you update appropriate record in the teams table.

    And so on.

    Thus, your data is (eventually) consistent and in sync with the write side.

    Yes, you need to use joins in the read side to fetch data...

    If this normalized view does not satisfy read performance needs, then you can build a denormalized view from this normalized data. it requires an extra step to build the denormalized view, but to me, it is the most simple solution I can think of for now.

    Maybe you even will not need a denormalized view.

    After all (in my opinion), the main value of ES is capturing user intent, confidence in your data (no destructive operations, single source of truth), ability to answer questions that nobody could think of in the past, big value for analytics.

    As I said, if you need to optimize performance, you always can build a denormalized view from the normalized view of the read side.

    0 讨论(0)
提交回复
热议问题