I'm stuck on finding the proper way to refer to entities located inside an aggregate root, when we only got their identities coming from URL parameters. I asked a previous question which ended up focused on value objects, so I'm starting with another example here.
Let's say we want to modify an OrderLine
inside an Order
:
edit-order-line?orderId=x&orderLineId=y
Now if I need to update the quantity in the OrderLine, I can do:
Order order = orderRepository.find(orderId);
order.updateQuantity(orderLineId, 2);
However, I don't feel very comfortable with the idea of leaving the responsibility to the Order to retrieve parts of itself by Id. My view on the subject is that within the domain, we should just talk with objects, and never with Ids. Ids are not part of the ubiquitous language and I believe they should live outside of the domain, for example in the Controller.
I would feel more confident with something like:
Order order = orderRepository.find(orderId);
OrderLine orderLine = em.find(OrderLine.class, orderLineId);
order.updateQuantity(orderLine, 2);
Though I don't like the idea of interacting directly with an Entity Manager, either. I feel like I'm bypassing the Repository and Aggregate Root responsibilities (because I could, potentially, interact with the OrderLine directly).
How do you work around that?
An aggregate root is a class which works as an entry point to our aggregate. All business operations should go through the root. This way, the aggregate root can take care of keeping the aggregate in a consistent state. The root is what takes cares of all our business invariants.
[Evans] states that one Aggregate may hold references to the Root of other Aggregates. However, we must keep in mind that this does not place the referenced Aggregate inside the consistency boundary of the one referencing it. The reference does not cause the formation of just one whole Aggregate.
Thus, the aggregate root must be an entity, not a value object, so that it can be persisted to and from a data store using its ID.
In domain-driven design, an entity is a representation of an object in the domain. It is defined by its identity, rather than its attributes. It encapsulates the state of that object through its attributes, including the aggregation of other entities, and it defines any operations that might be performed on the entity.
In my opinion there is nothing wrong with this approach:
Order order = orderRepository.find(orderId);
order.updateQuantity(orderLineId, 2);
orderLineId
is a 'local identity'. It is specific to aggregate root and does not make sense outside of it. You don't have to call it an 'id', it can be 'order line number'. From Eric Evan's book:
ENTITIES inside the boundary have local identity, unique only within the AGGREGATE.
...only AGGREGATE roots can be obtained directly with database queries. All other objects must be found by traversal of associations.
OrderLineId is what exactly? It has no meaning. You're updating the quantity of a PRODUCT and that's what should be used as the id.
Order order = orderRepository.find(orderID);
order.updateQuantity(productID, 2);
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With