Корень Group
является корнем агрегата. Membership
имеет смысл только по отношению к группе, и поэтому должен принадлежать этой совокупности, которая должна обеспечивать соблюдение инвариантов, связанных с членством в группе, например, запрещать добавление членства в закрытые группы.
Технически, гидратация Group
не требует, чтобы все его Membership
находились в памяти. Вы можете реализовать ленивую загрузку для Membership
s.
По практическим причинам вам, вероятно, понадобится User
в вашей модели, который будет действовать как прокси для User
, управляемых в другой системе. Этот User
будет корнем своего собственного агрегата, потому что User
существует независимо от Group
и должен быть доступен напрямую, не проходя через корень агрегата.
Судя по вашему описанию, вам нужна двунаправленная навигация: User
будет поддерживать коллекцию UserMemberships
к Groups
, членом которой он является. Эта совокупность будет отвечать за соблюдение User
инвариантов в вашей модели, таких как ограничения на количество групп, в которых может состоять пользователь.
Поскольку добавление пользователя в группу включает два различных агрегата, каждый из которых отвечает за свои собственные инварианты, эта операция будет сервисом в смысле DDD.
Рекомендую посмотреть эти видео для лучшего погружения в вопрос: