Search code examples
.netasp.net-coredomain-driven-designclean-architecture

DDD and many to many aggregate route relationship


I am new to DDD and I am strugling with the concept of aggregate routes and it's implementation in ASP .NET Core.

Basicaly, I have two aggregate routes (AR):

  • User
  • Group

Where there can be a group with multiple users and each of it's user can belong to many different groups.

If I correctly understand it, the rule relationships aggregate routes are following:

  • aggregate route should be serializable (no circle relationship)
  • aggregate route must not have navigation property pointing to another aggregate route

The fact, that one AR should not have navigation property to another means, that I have to connect them in some kind of different way, for example with ValueObject.

ValueObject:UserToGroup (can't have navigation properties cause of serializability)

  • GUID UserId
  • GUID GroupId

AR User:

  • GUID Id
  • ICOLLECTION< UserToGroup > Groups

AR Group

  • GUID Id
  • ICOLLECTION< UserToGroup > Users

With this setup I managed to get everything according to the rules. But one unexplained question arises. How do I query for all Users from a Group?? I could for example do this (with LINQ): var ids = group.Users.Select(g => g.UserId) var usersFromGroup = userRepository.FetchByIds(ids)

But this seems kind of stupid, I felling like I am basically killing one of the EF best features, navigation properties...

Any suggestions how to implement this in some kind of better way??

Thank you so much for your response.

Bruno


Solution

  • My recommendation would be to never query the domain model.

    There may be a few instances where the complete data you need in a query would be available/surfaced in a particular instance of a domain object (aggregate root). But this more-often-than-not is not the case.

    Queries should be a specific concern and be as close to the data store as possible. Typically the data is either returned in some low-level data structure such as a DataRow or perhaps a read model (data transfer object). A domain object should never cross a wire (well, that's my take on it).

    For querying I would use an implementation of an ISomethingQuery where my domain interaction would be through the ISomethingRepository. In this way you can stay away from navigation properties and oddities such as "lazy-loading". You can be specific with the data you need.

    The above structure usually leads to a situation where an ORM doesn't necessarily add much value but YMMV.