Search code examples
ormdomain-driven-designrepository-patternddd-repositories

Repository pattern, POCO, ORM and intermediate entities


I am trying to figure out how to address this issue:

I have 3 tables with a many-to-many relationship.

Users *-* Roles *-* Permissions

I use a ORM to obtain data from them.

A method of my business layer must return users per permission, so I return objects with this class:

public class UsersPerPermission
{
    public User[] {get;set;}
    public Permission {get;set;}
}

But this class does not map to any table in the repository, it is something I generate from the existent tables. Where should this class live?

In other words:

  • Should I have a IRepository.GetUsersPerPermission()? And then that class should live in the repository.

  • Or should I have a IBusinessLayer.GetUsersPerPermission()? And then I have to invoke the CRUD methods in the repository?

It makes sense to put it in the business layer only, because the repository should just expose CRUD operations to tables... BUT, in order to execute this operation from the Business layer, I would have to execute several independent queries to get the data and create the 'UserPerPermission' class. In the other hand, if I place it in the repository, I can get that information in one shot using grouping.

Thanks!

PS: What is the name of this intermediate objects? 'transformations'?


Solution

  • In DDD, most entities and value objects should correspond to identified domain concepts that are part of your ubiquitous language. I usually try to limit many-to-many relationships and artificial association objects as much as possible. Eric Evans describes a few techniques allowing that in his book. When I have to create an association object, it must have a meaningful name with regard to the domain, basically I never name it Class1ToClass2. In your scenario, it's even more artificial since your object :

    • Redundantly models an association that already exists (indirectly) in the original model.
    • Has a name that doesn't reflect any particular business concept.

    Note that this kind of object wouldn't be useless if we were in the presentation or application layer as it could come in handy to have a structure containing exactly what is displayed on the screen (DTO). But I'm talking about the domain layer here, which should be devoid of such composite objects.

    So I wouldn't create a UsersPerPermission class in the first place. If what you want is a list of users and User is an aggregate root, just create a GetUsersByPermission() method in UserRepository. It doesn't mean that you can't have a GetUsersByPermission() method in an application service as well, if it matches a use case of your application (a screen that displays the details of one permission and the list of users with that permission).