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?
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.
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.
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.
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.
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.
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.
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.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With