Aggregates are groups of things that belong together. An Aggregate Root is the thing that holds them all together. When trying to form aggregates, the rule “is part of” … that may help make the decision.
The obvious example following on is Orders and OrderLines. The OrderLines are part of the Order, they just happen to be represented as a different thing to make operations easier. Customer may have a reference to the customer’s Orders. An Aggregate is slightly different, where as Customers and Orders can exist in the system independently.
OrderLines have no reason to exist without their parent Order, nor can they belong to any otherOrder. In this case, Order and OrderLines would probably be an Aggregate, and the Order would be the Aggregate Root. Add a new OrderLine, or to change an OrderLine, you would tell the Order to make the changes.
If the parent, in this case the Order, was deleted all other parts of that Aggregate below Order would be deleted too. So if it doesn’t make sense that a parent being deleted would also delete all children, then you don’t have an Aggregate.
In the case of an ExamPaper, the Questions are a part of it, if the Questions are never used elsewhere or in another way . The Results for the paper are not part of the Paper, and the Results are not part of the ExamCandidate. Results are also not a part of the ExamPaper nor are individual Resuls part of the Question.
Why Aggregates ?
Aggregates provide a clean pattern to keep logic where it really belongs. Another aspect of Aggregate Roots is that they are the Entities that are dealt with by Repositories. In examples above, we would have a Customer Repository, and an Order Repository, but there would not be an OrderLine Repository. It is the responsibility of the Repository for the Aggregate Root to deal with persistence of all the children of that Aggregate.
The main, and possibly obvious restriction on Aggregate Roots is, they must be Entities, and cannot be Value Objects. Entities have Identity, andValue Objects do not – you could not ask a Repository to retrieve an Aggregate Root if it had no Identity.
Within an Aggregate, the other players can be Entities or VOs as the domain dictates. For example, expanding our Order example further, the Aggregate may comprise the Order (Aggregate Root), theOrder may have an OrderNumber (Value Object), some OrderLines (Entities), and a Shipping Address and Billing Address (Value Objects)
Entities can hold references to any Aggregate Root, but never to any other Entity or VO within the Aggregate. To access any other part of the Aggregate, you must navigate from the Aggregate Root.
How the component parts of an Aggregate are persisted is a matter for the implementation behind Repository, but if you were using an ORM like NHibernate for example, the changes are that the Value Objects would be NHibernate Components nested in their parent entity record and the Entities would be old fashioned mappings, each with their own table.
Aggregates provide a logical grouping of Entities and Value Objects that belong together at all times. An Aggregate Root is the gatekeeper to the Aggregate. Each Aggregate is treated as a single unit for persistence purposes.
By logically grouping Entities and VOs in this way, we provide a mechanism to strictly manage a grouping of objects, and a way to allow us to treat a number of different Entities and VOs as one.