Suppose i have two classes:
Order
OrderItem
What connection is the correct one from the standpoint of DDD?
OrderItem containing a field referencing the Order
Order having a field - collection of OrderItems
Is a field referencing another object interpreted as a dependency?
I am trying to understand DDD better.Thanks.
I'll make an assumption here and consider your Order class to be the aggregate root.
In that case you would go with the option 2, meaning an Order then would contain a collection of OrderItems. And OrderItems could only be added via Order Aggregate root, ie. via method Order.AddOrderItem().
Related
In my domain model I have the project entity (which is also aggregate root) which has products entity as child. One of the invariants of my domain model is that I can't have two products with the same code children of the same project (but is ok if the project is different).
My products are composed by parts which also has a similar rule (every part must have unique code within the same product) so parts are child of products because I need to ensure that rule. Children of product are also the activities that I need to do to create it because I'm describing a production tracking system.
Now, activities can have subactivities which can be assigned to factory area and so on.
Substantially what I have is that all entities starts from project just because I need to ensure one invariant(=business rule) but is not the best solution because every time I need to retrieve an entity I need to fill all the project (which can have 2000+ products).
What can I do to split that preserving my invariant but also freeing me to load a specific activity (or product) without retrieving all products of my project every time I need a child entity?
Should I need to split the Entities in several AggregateRoots, maintaining in the project a list of ProjectProductValueObject(string code) and use Domain Events in Aggregate's constructor to fire something like ProductCreatedEvent which try to create and add a new ProjectProductValueObject in my project using the AddProduct(ProjectProductValueObject product) method which contain my business rule and throws an exception if that's not satisfied? Is that ok and compliant to DDD principles?
Do I have other alternatives?
I have the feeling that you're overcomplicating the model.
From your description I've understood that:
Projects are root entities that can contain a list of
AssignedProduct, that is another root entity that contains a binding between the project (its id, see as a value object) and the product (I see it also as a value object)
So on with object and assigned object
In this way you've several Products that could be assigned to several Projects, but only the ones stored in AssignedProduct are valid. To avoid multiple assignments is just a matter of checking if the same couple of objects are already bound together.
If this doesn't match your model, ignore it.
Lots of examples like order and order lines makes sense, like:
Order is an AR that contains OrderLines
Customer is an AR that contains Orders.
Question is, what is the AR that contains Customer?
I guess it can be something like "shop".
So, shop.AddCustomer(customer)...
but, how to get shop?
If it's an AR (entity) it has an id, so shop.GetById(shopId). If I only have one shop, how does this work with persistence?
Should I have a table (shops) with one line?
Shop is an in-memory object with a collection of Customers?
You got that wrong there. Aggregates do not contain other aggregates! They can only reference them by ID.
An aggregate is a group of entities and value objects that are closely related. The aggregate forms a consistency boundary around them. The Aggregate Root is the root entity in that aggregate that is globally addressable. So in your example with Order and OrderLines, Order could indeed be the AR.
Customer on the other hand, would only reference Orders by ID if it is a separate aggregate.
To retrieve an aggregate, you typically use a Repository. You load an aggregate through the repository by specifying the ID of the aggregate, or some other suitable search parameter.
Question about using Aggregates (not AR) in Domain Driven Design.
Using the familiar: Order (aggregate root [AR]) and OrderLine (aggregate member [AM]) works for an example. If one assumes that the Orders are persisted, then how does one, properly from a DDD perspective, operate on the aggregate members?
For instance, can I search (find operation) for all the OrderLines of a given item? What is the correct way to do that? If I return those as Value Objects, that just seems wrong, in reality they are persisted Domain Objects. Furthermore, I might need to be able to get the Order from one of them. Yet, if I return them (from the Repository layer) as Entity objects, then I seem to have violated the Aggregate Root canonical rule.
I think I have the answer to my question. If I now follow correctly, it's completely okay to know about an entity below the aggregate root. However, one can not store/view/reference an ID to it. But you CAN reference the AR Id.
Thus, I can have say: OrderRepository.findOrderLines(withProductId) method that returns a list of OrderLine objects less their Id, but having the Order Id (AR ID) on those objects is fine.
Please comment if this is off-base.
I am currently working through the domain driven design book by Eric Evans, and there is one concept that I am having trouble with...
According to the book, all aggregates should have an aggregate root, and all members of the aggregate should only be accessed via this root. The root should also be responsible for enforcing invariants. Will this not lead to a lot of method duplication though? Take for example the following scenario:
I have a class Order, that consists of a set of OrderLine's. Class Order is the aggregate root in this case, and it must enforce the invariant that all OrderLine's of a single Order must have a unique order number. To ensure that this invariant is not violated, class Order does not expose its OrderLine's, and simply offers a method updateOrderLineOrderNumber(long orderLineId, int newOrderNumber) via which OrderLines must be updated. This method simply checks whether the newOrderNumber does not conflict with an existing order number, and then calls the method updateOrderNumber(int newOrderNumber) of the appropriate OrderLine. This is fine, since it is only one method, but what happens when class OrderLine has a couple of methods? Since an Order does not expose its OrderLines, all properties of OrderLines will have to be updated via class Order, even if the property changes don't need any invariant checking. This will undoubtedly lead to a lot of method duplication, which will only get worse as more classes are added to the aggregate.
Am I understanding this wrong? Is there any alternative mechanisms or design patterns that I could use to prevent this scenario?
One possible strategy that I thought of using is the concept of validators. Whenever a property of an OrderLine is changed, it must first check with a set of validators whether this change is allowed. The Order can then add an appropriate validator to an OrderLine's name property whenever the OrderLine is added to an Order. What do you guys think of this strategy?
Any help or thoughts would be greatly appreciated!
I don't see a problem here to be honest. Firstly why would you want to change orderId? Id should be set once, different id equals different entity.
Usually if you want to update entity of an AR you just get it and update it.
orderLine = order.getOrderLine(index)
orderLine.changeProduct(someProduct)
If you need to keep some invariants in AR, in example that OrderLine.product must be unique, then you call AR method.
order.changeOrderLineProduct(orderLineIndex, someProduct)
Internally that method checks if someProduct is unique and if it is then calls code above.
There is no DRY violation in this, AR method checks invariants, orderLine method updates.
I would also think about using more UL in this, like "Client changes product on his orderline on order"
client.changeOrderLineProductOnOrder(orderLineIndex, product, order)
This way you can check if client is an owner of that order.
I have a domain model
Customer - Aggregate root - because an order can't exist without a customer
Order - entity
OrderStatus - value object
In my form I need a list of all OrderStatuses.
Should I fetch an empty customer entity(AR) from repository with an empty order entity which is containing a list of all OrderStatuses? This is awkward.
Well, it always depends on your problem domain, but lacking further info, I would say you probably need to break your modeling a little bit.
Even though an Order can't exist without a Customer, it will not be a child entity under the Customer AR. You need to introduce the notion of Bounded Contexts.
Customer would be the AR of one BC, while Order would be the AR of its own BC.
In that case, you would reference Customer from Order with a CustomerId property (not with an object reference) because they belong to different contexts, and as such they could even live in separate microservices, in separate databases.
You see where I'm going: it makes no sense to fetch an empty Customer, with an empty Order (or list of Orders) just to reach a list of Order Statuses.
Even if Order and Customer did belong to the same BC, OrderStatus is Reference Data, and would be better represented by an enum type (or better, with the Enumeration Pattern).
Have a look at this additional info:
Reference data as code
Entities, Value Objects, Aggregates and Roots