Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

DDD Aggregate Root / Repository Structure

I am new to this, so my understanding is still flaky.

I have a Person model and an AccountType model in my project. Each person references an account type.

Now if my understanding is correct a Person is definitely an aggregate root, whereas the AccountType probably isn't as the entries in the account type table are going to be pretty much static and are certainly have no meaning outside of a Person.

However when I create a new person I need to set the account type, so it would seem I need a repository to access the account type to assign to the user, but the repository code I have only allows aggregate roots to be accessed.

What would be the correct way to structure this?

like image 931
Dale K Avatar asked Aug 07 '12 08:08

Dale K


People also ask

What is an aggregate root DDD?

An aggregate root is a class which works as an entry point to our aggregate. All business operations should go through the root. This way, the aggregate root can take care of keeping the aggregate in a consistent state. The root is what takes cares of all our business invariants.

Can aggregates use repository?

Because aggregates are the consistency boundaries exposed to the application layer. Which is to say that, yes, the repositories are responsible for taking the snapshot of state from the data store, and building from it the graph of entities and values that make up the aggregate.

Is an aggregate root an entity?

Thus, the aggregate root must be an entity, not a value object, so that it can be persisted to and from a data store using its ID. This is important, since it means the aggregate root can be certain that other parts of the system are not fetching its children, modifying them, and saving them without its knowledge.

What is aggregate root in C#?

Aggregate root are cluster / group of objects that are treated as a single unit of data. I am sure lots of developers are already using this pattern unknowingly, via this short note I would like to inform you formally what you are doing.


2 Answers

I think that AccountType is another aggregate root which is referenced from the Person aggregate root. It's absolutely normal to have many simple aggregate roots, see Vaughn Vernon articles, see part 1, p. 5:

On one project for the financial derivatives sector using [Qi4j], Niclas [Hedhman] reported that his team was able to design approximately 70% of all aggregates with just a root entity containing some value-typed properties. The remaining 30% had just two to three total entities. This doesn't indicate that all domain models will have a 70/30 split. It does indicate that a high percentage of aggregates can be limited to a single entity, the root.

In your question it's not quite understood, what is the problem with accessing repositories to initialize the aggregate root's properties:

However when I create a new person I need to set the account type, so it would seem I need a repository to access the account type to assign to the user, but the repository code I have only allows aggregate roots to be accessed.

The initialization of the Person class should be handled by PersonFactory.

The PersonFactory is a service, so it can have reference to AccountTypeRepository to find a suitable AccountType instance and return a fully constructed Person instance of that type.

update: Also I'd like to add a note that referencing your AccountType by id works equally well. It's all matter of convenience, sometimes it's more convenient(only for displaying, not for modifying, of course) to access the references directly if you use GUI frameworks with rich data binding capabilities like WPF or Spring MVC so you can directly access this properties to display in View. If you are using the id approach, this may force you to create ViewModels (FormBeans) even for the simple Entities.


Regarding the lookup-based solution, it works well for very simple enum-like fields, I suppose that AccountType is something more complex than that and belongs to the knowledge level (see the discussion of the question).

Returning to the choice between aggregates and value object(also see this), it depends on the abstraction level and configuration capabilities of your information system. From the point of view of the Account class it may look like a value object, you can replace one AccountType with another: it will be just like switching between Color value objects, but from the point of the knowledge level your user may want to customize the behavior of the system for selected AccountType, for example change discounts for specific "Premium" accounts. So if you have the knowledge level, AccountType will be something with an identity which leads you to creating a separate repository.

like image 106
Boris Treukhov Avatar answered Jan 04 '23 16:01

Boris Treukhov


The most important thing is (assuming AccountType has an entity with an ID and is not a simple enum)...

Account Type and Person should only reference each other by ID.

like image 40
Josh Kodroff Avatar answered Jan 04 '23 17:01

Josh Kodroff