Search code examples
domain-driven-designevent-sourcingaggregaterootdomain-events

Loading aggregates on reacting to domain events


I am implementing an application with domain driven design and event sourcing. I am storing all domain events in a DomainEvents table in SQL Server.

I have the following aggregates:

- City
   + Id
   + Enable()
   + Disable()

- Company
   + Id
   + CityId
   + Enable()
   + Disable()

- Employee
   + Id
   + CompnayId
   + Enable()
   + Disable()

Each one encapsulates its own domain logic and invariants. I designed them as separate aggregates, because one city may have thousands (maybe more) companies and company may also have very large number of employees. If this entities would belong to the same aggregate I had to load them together, which in most cases would be unnecessary.

Calling Enable or Disable will produce a domain event (e.g. CityEnabled, CompanyDisabled or EmployeeEnabled). These events contain the primary key of the enabled or disabled entity.

Now my problem is a new requirement forcing me to enable/disable all related Companies if a City is enabled/disabled. The same is required for Employees, if a Company is enabled/disabled.

In my event handler, which is invoked if for example CityDisabled has occurred I need to execute DisableCompanyCommand for each company belonging to that city.

But how would I know what companies should be affected by that change?

My thoughts:

  1. Querying the event store is not possible, because I can't use conditions like 'where CityId = event.CityId'

  2. Letting the parent know its child ids and putting all child ids in every event the parent produces. Is also a bad idea because the event creator shouldn't care who will consume the events later. So only information belonging to the happening event should be in the event.

  3. Executing the DisableCompanyCommand for every company. Only the companies having the matching CityId would change their state. Even though I would do that asynchronously it would produce a huge overhead loading every company on those events. And also for every company getting disabled the same procedure should be repeated to disable all users.

  4. Creating read models mapping ParentIds to ChildIds and loading the childIds according to the parentId in the event. This sounds like the most appropriate solution, but the problem is, how would I know if a new Company is created while I am disabling the existing ones?

I am not satisfied with any of the solutions above. Basically the problem is to determine the affected aggregates for a happened event.

Maybe you have better solutions ?


Solution

  • What you are describing can be resolved by a Saga/Process manager that listen to the CityDisabled event. Then it finds the CompanyIds of all Companies in that City (by using an existing Read model or by maintaining a private state of CityIdsxCompanyIds) and sends each one a DisableCompany command.

    The same applies to CompanyDisabled event, regarding the disabling of Employee.

    P.S. Disabling a City/Company/Employee seems like CRUD to me, these don't seem terms from a normal ubiquitous language, it's not very DDD-ish but I consider your design as being correct in regard to this question.