Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Simple aggregate root and repository

I'm one of many trying to understand the concept of aggregate roots, and I think that I've got it! However, when I started modeling this sample project, I quickly ran into a dilemma.

I have the two entities ProcessType and Process. A Process cannot exist without a ProcessType, and a ProcessType has many Processes. So a process holds a reference to a type, and cannot exist without it.

So should ProcessType be an aggregate root? New processes would be created by calling processType.AddProcess(new Process()); However, I have other entities that only holds a reference to the Process, and accesses its type through Process.Type. In this case it makes no sense going through ProcessType first.

But AFAIK entities outside the aggregate are only allowed to hold references to the root of the aggregate, and not entities inside the aggregate. So do I have two aggregates here, each with their own repository?

like image 996
Vern Avatar asked Feb 07 '11 13:02

Vern


1 Answers

I largely agree with what Sisyphus has said, particularly the bit about not constricting yourself to the 'rules' of DDD that may lead to a pretty illogical solution.

In terms of your problem, I have come across the situation many times, and I would term 'ProcessType' as a lookup. Lookups are objects that 'define', and have no references to other entities; in DDD terminology, they are value objects. Other examples of what I would term a lookup may be a team member's 'RoleType', which could be a tester, developer, project manager for example. Even a person's 'Title' I would define as a lookup - Mr, Miss, Mrs, Dr.

I would model your process aggregate as:

public class Process
{
     public ProcessType { get; }
}

As you say, these type of objects typically need to populate dropdowns in the UI and therefore need their own data access mechanism. However, I have personally NOT created 'repositories' as such for them, but rather a 'LookupService'. This for me retains the elegance of DDD by keeping 'repositories' strictly for aggregate roots.

Here is an example of a command handler on my app server and how I have implemented this:

Team Member Aggregate:

public class TeamMember : Person
{
    public Guid TeamMemberID
    {
        get { return _teamMemberID; }
    }

    public TeamMemberRoleType RoleType
    {
        get { return _roleType; }
    }

    public IEnumerable<AvailabilityPeriod> Availability
    {
        get { return _availability.AsReadOnly(); }
    }
}

Command Handler:

public void CreateTeamMember(CreateTeamMemberCommand command)
{
    TeamMemberRoleType role = _lookupService.GetLookupItem<TeamMemberRoleType>(command.RoleTypeID);

    TeamMember member = TeamMemberFactory.CreateTeamMember(command.TeamMemberID,
                                                           role,
                                                           command.DateOfBirth,
                                                           command.FirstName,
                                                           command.Surname);

    using (IUnitOfWork unitOfWork = UnitOfWorkFactory.CreateUnitOfWork())
        _teamMemberRepository.Save(member);
}

The client can also make use of the LookupService to populate dropdown's etc:

ILookup<TeamMemberRoleType> roles = _lookupService.GetLookup<TeamMemberRoleType>();
like image 56
David Masters Avatar answered Oct 02 '22 02:10

David Masters