1

I'm developing an event-sourced/CQRS application and do not understand the best strategy to use when building the read model projections when additional domain data is needed. A partial representation of the write model aggregates and events are as follows ...

WorkOrder

  • workOrderId
  • workOrderNumber
  • warehouseId

WorkOrderCreatedEvent

  • workOrderId
  • workOrderNumber
  • warehouseId

Warehouse

  • warehouseId
  • warehouseName

WarehouseNameUpdatedEvent

  • warehouseId
  • oldWarehouseName
  • newWarehouseName

I'm developing a read model which looks as follows ...

WorkOrderReadModel

  • workOrderId
  • workOrderNumber
  • warehouseName
  • workOrderStatus

I'm running into an issue when trying to represent the warehouseName in the WorkOrderToBeReceivedModel. When the WorkOrderCreatedEvent is thrown, the projector picks up this event but only has access to the warehouseId and not warehouseName. I see three approaches for solving this problem, however, I’m not sure which one is the best …

  1. Modify the WorkOrderCreatedEvent and include warehouseName in addition to warehouseId. I will then have access to the name in my projection and can persist it at the time of creation. This would work, however, as soon a warehouse name was updated, the data would become stale. I can listen to the WarehouseNameUpdatedEvent in this projection, however, this would become cumbersome when adding additional fields for related aggregates (ie CreatorId, ProductId, etc.). The upside to this approach is that I am not adding dependencies on other projections or repositories from the write side.
  2. Inject the aggregate write model warehouseRepository into the projector, and then use this repository to reconstruct the warehouse from the event store and access the name. I’ve now added a dependency on the write model. I’m not sure if this is an anti-pattern in the ES/CQRS world. In addition, the data will still become stale the same way as mentioned for 1.
  3. Build a warehouse read model projection and then join to this table from the work order projection. I’m making things a bit fragile by depending on another projection and might run into issues if the warehouse projection is not “in-step” with the work order projection.

Any advice would be appreciated.

0

Option 1: WorkOrderCreatedEvent including the warehouseName would make the construction of the event more complex as now you have to query for the WareHouse for construction the event. This complexity is not justifiable for me. One of the biggest benefits of the CQRS to me is to remove the complexities introduced by various shapes of the read data.

Option 2: If the read model and write model are separated as two different applications, and both the application are having separate code base, then I think your concern is valid. If you have the same code base for the read and write models and deploying it by configuring it, then I think this is okay. In this option why not additionally listen to the "WarehouseNameUpdatedEvent" to avoid data becoming stale.

Option 3: I would prefer for each projection to have their own tables. I would not share the tables between projection. This could keep the projection less complex.

Option 4: (Not listed) build a WorkOrderReadModel projection, and listen to WarehouseNameUpdatedEvent and WorkOrderCreatedEvent and store the data in normalized form. (you will have a WareHouse table and WorkOrder table). Then while query, join the table build the projection.

Option 5: (Not listed) Modify option 2 and make a http call to write model application to get the warehouse name while you get the work order created event. You might need to listen to WarehouseNameUpdatedEvent

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.