Event handling for non-root aggregates

Suppose a model with Customer as AggregateRoot.
A customer can register an Order, hence you get a series of order
related events (created, updated, deleted)
An order contains multiple Orderlines, hence you get a similar serie
of orderline related events.

The OrderCreatedEvent triggers an addition of the order to a
collection of orders. This event is clearly handled inside the
Customer AggregateRoot.

However, for orderlines I find this unsettling. It doesn't seem right
to me, to handle orderlines event inside the customer class which
doesn't know anything about offerlines.

Would you make Order an Aggregate which would be able to handle the
offerline events? If so, how do you filter the right order to handle
the offerline events?

Please share your thoughts

regards
Roald

Hi Roald,

making the Order entity part of a Customer aggregate sounds a bit awkward to me. But let’s assume for now that it has to be.

There is currently a limitation in Axon that requires all events to be applied to the aggregate root. In the ideal case, you apply them to the aggregate, which would mean that any entity inside the aggregate could handle them. Issue 58 (http://code.google.com/p/axonframework/issues/detail?id=58) should provide the ability to have events handled directly by entities inside an aggregate.

But if you say that a Customer should not know anything about OrderLines, then that is probably a good sign that they should not be part of the same aggregate. What I typically see in these cases, is that Customer is an aggregate, and Order+Orderline another.

Hope this helps,

Allard

Hi Roald,

  • So if you remove a customer, you want to remove all his orders as well?- Is a customer one person, or can it be multiple persons?
  • Is an order only important in relation to the customer, or can it be important to stock, invoice, accounting, statistics

Often an order belongs to a customer but it is not part of the customer. Are you going to change state of the order through the customer? What if you keep the status of an order like, ready to be shipped. Do you want to expose that via the customer?

Good that you now have an offer, will an offer result in an order? Is it an order with a certain state?

Just some thoughts :slight_smile:

greetz Jettro

> Do you have any thoughts about how to keep the Customer class maintainable?

> regards Roald

Hi Roald,

I think the issue 58 (http://code.google.com/p/axonframework/issues/
detail?id=58) Allard evoked in his reply would really help to keep
aggregate roots very maintainable.
Via @Entity annotations, aggregate roots would be able to "delegate"
handling of events to its entities, hence no more "monster aggregate
root" regarding event handling.

Cheers,
Lionel.

Hi Roald,

the reason for choosing to put an entity within an existing aggregate, or on it’s own, is not a matter of which-was-there-first. Otherwise, the “User” would always be the aggregate root of the entire system.

Instead, the choice for an aggregate is about consistency boundaries. Information inside an aggregate is always consistent. No matter what happens. Information between aggregates is eventually consistent, or even inconsistent, if you want. An order can only be created for a certain customer, but can it only exist with a customer? Is there any information in the customer that changes the behavior of an order, or vice versa? And if so, is it really unacceptable to have that information to be eventually consistent.

The problems you are having are, for me, a clear indication that something is wrong with aggregate boundaries. I would create an Order (or offer) aggregate that is given a customer ID upon creation. Your command handler can validate whether the ID really exists, if that is necessary. Information in the customer aggregate can be updated through event listeners that listen for changes in the orders. For example to mark a customer as being a “high value customer”.

Just some for for thought. Every case is different. Though be very careful when using a relationship between entities as a primary reason for aggregate boundary choices. You’ll most likely end up with monster aggregates that are not easy to deal with.

Cheers,

Allard