2

I'm having trouble understanding how one would access the sub entities of an aggregate root. From answers to my previous question I now understand that I need to identify the aggregate roots of my model, and then only setup repositories which handle these root objects.

So say I have an Order object that contains Items. Items must exist within and Order so the Order is the aggregate root. But what if I want to include as part of my site an OrderItem details page? The URL to this page may be something like /Order/ItemDetails/1234, where 1234 is the ID of the OrderItem. Yet this would require that I retrieve an Item directly by ID, and because it is not an aggregate root I should not have a OrderItemRepository that can retrive an OrderItem by ID.

Since I want to work with OrderItems independent of an Orders does that imply that OrderItem is not actually an aggregate of Order but another aggregate root?

Community
  • 1
  • 1
Eric Anastas
  • 21,675
  • 38
  • 142
  • 236
  • I would consider OrderItem as a value object since it has no real mening without the context of an order. – alexn May 18 '11 at 07:30
  • OrderItem is an entity and not value object cause it have to have identity. From business perspective 2 OrderItems for same amount of product may not be equal – xelibrion May 18 '11 at 09:25
  • Also you could post your question to Google DDD/CQRS group which has very active community https://groups.google.com/forum/#!forum/dddcqrs – xelibrion May 18 '11 at 09:27
  • @Xeilbrion Of course. Must have been tired in the morning. – alexn May 18 '11 at 17:11

2 Answers2

1

I don't know your business rules, of course, but I can't think of a case where you would have an orderitem that doesn't have an order. Not saying you wouldn't want to "work with one" by itself, but it still has to have an order, imo, and the order is sort of in charge of the relationship; e.g. you would represent all this by adding or deleting items from an order.

In situations like this, I usually will still require access to the items through the order. It's pretty easy to setup, in URLs I would just do /order/123/item/456. Or, if item ordering is stored / important (which it normally is stored at least indirectly via the order of entry), you could do /order/123/item/1 to retrieve the first item on the order.

In the controller, then, I just retrieve the order from the OrderRepository and then access the appropriate item from there.

All that said, I do agree w/ Arnis that you don't always have to follow this pattern at all. It's a case-by-case thing that you should evaluate the tradeoffs before doing it.

Paul
  • 35,689
  • 11
  • 93
  • 122
0

In Your case, I would retrieve OrderItem directly by URL /OrderItem/1234.

I personally don't try to abstract persistence (I don't use repository pattern). Also - I don't follow repository per aggregate root principle. But I do isolate domain model from persistence.

Main reason for that is - it's near-impossible to abstract persistence mechanisms completely. It's a leaky abstraction (e.g. try specifying eager/lazy loading for ORM that lives underneath w/o polluting repository API).

Another reason - it does not matter that much in what way You report data. Reporting part is boring and relatively unimportant. Real value of application is what it can do - automation of processes. So it's much more important how Your application behaves, how it manages to stay consistent, how objects interact etc.

When thinking about this problem, it's good to remember Law of Demeter. The point is - it should be applied only if we explicitly want to hide internals. In Your case - we don't want to hide order items.

So - exploiting fact that we know that entity Ids are globally unique (as opposed to unique only in Order context) it's just a short-cut and there is nothing wrong with retrieving them directly.


Interestingly enough - this can be pushed forward.
Even behavior encapsulation can and should be loosened up too.

E.g. - it makes more sense to have orderItem.EditComments("asdf") than order.EditOrderItemComments(order.OrderItems[0], "asdf").

Arnis Lapsa
  • 45,880
  • 29
  • 115
  • 195