I am trying to get my hands dirty learning DDD (by developing a sample eCommerce site with entities like Order
, OrderLines
, Product
, Categories
etc).
From what I could perceive about Aggregate Root concept I thought Order
class should be an aggregate root for OrderLine
.
Things went fine so far, however I am confused when it define a create order flow from UI.
When I want to add an order line to my order object, how should I get/create an instance of an OrderLine
object:
OrderLine()
statement in my UI/Service class productID
, quantity
etc in Order
class?Also, what if I want to remove the hardcoded instantiations from the UI or the Order
class using a DI. What would be the best approach for this?
When choosing an aggregate root you choose between Transactional Consistency and Eventual Consistency. When your business rules allow you would rather favour Eventual Consistency.
An aggregate is a collection of one or more related entities (and possibly value objects). Each aggregate has a single root entity, referred to as the aggregate root. The aggregate root is responsible for controlling access to all of the members of its aggregate.
[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.
Aggregate is a pattern in Domain-Driven Design. A DDD aggregate is a cluster of domain objects that can be treated as a single unit. An example may be an order and its line-items, these will be separate objects, but it's useful to treat the order (together with its line items) as a single aggregate.
From what I could perceive about Aggregate Root concept I thought Order class should be an aggreagrte root for OrderLine.
Yes, OrderLine's should most likely be under an Order root, since OrderLine's likely make no sense outside of a parent Order.
Should I hardcode the new OrderLine() statement in my UI/Service class
Probably not, though this is how it happens often and it is made to work. The problem, as I see it, is that object construction often happens in different contexts, and the validation constraints differ depending on that context.
Should I define a method with parameters like productID,quantity etc in Order class?
As in:
public OrderLine AddOrderLine(Product product, int Quantity ... )
This is one way to do it. Notice I used a Product class instead of a ProductId. Sometimes one is preferable to the other. I find I use both a lot for various reasons - sometimes I have the ID and there's no good reason to pull the aggregate root, sometimes I need the other root to validate the operation.
Another way I do this is to implement a custom collection for the children.
So I have:
order.OrderLines.Add(product, quantity);
This feels a little more natural or OO, and in particular if an entity root has many child collections it avoids clutter.
order.AddOrderLine()
, order.AddXXX()
, order.AddYYY()
, order.AddZZZ()
versus
order.OrderLines.Add()
, order.ZZZs.Add()
, order.YYYs.Add()
Also, what if I want to remove the hardcoded instantiations from the UI or the Order class using a DI. What would be the best approach for this?
This would be a textbook case for the Factory pattern. I inject such a Factory into my custom collections to support instantiation in those Add()
methods.
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