We are trying to adopt Domain-Driven Design in our project for the first time. The problem I have is with associations between entities. How do you do them right?
Say, I've got entities Employee
and Contract
, a simple one-to-many association. How do I model it?
Option 1: Aggregate.
Problem: The problem here is that, if I understand it correctly, all entities in an aggregate must be loaded when an aggregate object is created. I can't lazy-load entities when they are needed because it would require referencing a repository from an entity, which apparently is bad. But fetching all of an employee's contracts from the database every time would be a big performance issue.
Option 2: Fetching an employee's contracts by using a repository (e.g. ContractRepository.GetContractsForEmployee()
) and adding EmployeeId
property to Contract
class.
Problem: it makes hard to put any business logic into entities. I would like to have a method, say, Employee.Dismiss()
, but it would also need to update the employee's contract. This means I would need to put this logic in a service. The problem is, I can't think of much logic operating only on an Employee
and thus the model would become somewhat anemic, with most logic inside services.
How do you deal with these issues in DDD?
This is just my take on it... without knowing your domain.
First, here is a good resource to read (part about Aggregates and Roots).
In DDD terminology, Employee
and Contract
are both entities (because they both have an identity).
"Aggregates draw a boundary around one or more Entities. and also: Each Aggregate has a Root Entity, which is the only member of the Aggregate that any object outside the Aggregate is allowed to hold a reference to."
The question is: do Employee
and Contract
form an aggregate, with Employee
being the root entity? Obviously not, because other domain entities could also have a reference to a contract
, and the contract id's are globally unique, not only within a Customer
.
So, taking into account these rules, Employee
and Contract
are both aggregate roots.
Then: "Only aggregate roots can be obtained directly with queries; so this means that we should have a repository per aggregate root."
So in this case, we have an EmployeeRepository
and a ContractRepository
.
Taking all of this into account, I would not add a relation between employees and contracts in the domain model; but treat them separately. After all, if you need an Employee
, you don't necessarily need his contracts
too, they are both different aspects.
Option 2 is what I would choose: use the ContractRepository
to get the contracts you are interested in. And if needed you could add a domain service that is responsible for aggregating employees and contracts if needed.
If you also define a Company
entity, then dismissing an employee could be the job of that entity.
We recently got into the DDD approach as well. If I were to do it, I would have the following (attributes are simplified for brevity):
public class Employee() {
String name;
Set<ContractNumber> contracts;
public void addContract(ContractNumber contractNumber) {
this.contracts.add(contractNumber);
}
}
public class Contract() {
ContractNumber contractNumber;
Date effectiveDate;
}
public class ContractNumber() {
String contractNumber;
}
ContractNumber is a Value Object that is referred to from within Employee. In this example, Employee is within a BoundedContext that deals with Employees and their respective contracts. There may be other representations of Employee in other bounded contexts.
As discussed in other answers, there will be repositories for both Employee and Contract.
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