domain-driven-designrepository-patternaggregateroot

Aggregate roots in DDD


I have registration form where user can input username and password and also create company at the same time(or chose one of existing companies). User have multiple companies and company have multiple users. How can I correctly choose User or Company to be my aggregate root(or both of them?).

I set Company as an aggregate root, it is ok in registration process I'm creating company and adding user to the company (company.addUsers(...)). But when I want to update user profile info(such as name, surname), I cannot do it in company aggregate root. I can create UserAggreageRoot and update user there but in this case it would affect to registration process(because in one transaction UserAggregate and CompanyAggregate would be updated, which is wrong).


Solution

  • An aggregate can be viewed as an entity that covers a consistency boundary for a particular action.

    If Company and User are in the same domain then you could use Company as an aggregate for creating users:

    public class Company
    {
        public List<User> Users { get; set; }
    
        public void AddUser(string forename, string surname)
        {
            User user = new User(forename, surname);
        }
    }
    
    public class User
    {
        public string Forename { get; set; }
        public string Surname { get; set; }
    
        public User(string forename, string surname)
        {
            Forename = forename;
            Surname = surname;
        }
    }
    

    Your command handler can then create the company and call AddUser and then add the company to the unit of work via a repository. You are only changing one aggregate (consistency boundary). When the unit of work is committed your infrastructure will add the company and user within one transaction.

    But then if you just want to change user's name (and there is no need for the Company to know about that) then you can retrieve a User an aggregate.

    A domain class can be an aggregate in one context but not in another.

    public class User
    {
        public string Forename { get; set; }
        public string Surname { get; set; }
    
        public User(string forename, string surname)
        {
            Forename = forename;
            Surname = surname;
        }
    
        public void SetForename(string forename)
        {
            Forename = forename;
        }    
        public void SetSurname(string surname)
        {
            Surname = surname;
        }
    }
    

    The command handler will retrieve the User from the repository (and add the user to the unit of work) and make the changes to user before committing the unit of work.