4

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'?

vtortola
  • 34,709
  • 29
  • 161
  • 263

3 Answers3

4

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).

guillaume31
  • 13,738
  • 1
  • 32
  • 51
  • The problem is that the application has a screen where you can see users grouped by permission. Following your approach, that is sound, I have to call 'GetUsersPermissions' and for each 'Permission' call 'GetUsersByPermission', what means a lot of queries to the DB. In the other hand, having this arificial aggregate I can get all in one query. – vtortola Sep 02 '12 at 13:48
  • 1
    How many permissions could you have ? If they are so numerous, can they all be displayed on the screen along with all their users in the first place ? Since the (hypothetical) performance problem comes from the UI, can't it be solved in the UI, by first displaying only Permissions and then the associated users if you click on a particular Permission ? Or just the first few Permissions+Users and lazy load the following ones on scroll ? ... – guillaume31 Sep 02 '12 at 22:26
  • 1
    Also, you might want to have a look at the great answers given here : http://stackoverflow.com/questions/5477506/how-to-implement-ddd-repository-to-handle-a-query-with-multiples-entities and here : http://stackoverflow.com/questions/2098112/ddd-how-to-implement-high-performing-repositories-for-searching – guillaume31 Sep 02 '12 at 22:27
  • There is going to be much more permissions than users, and I cannot bend the requirement to fit technical issues, the business wants that screen that way. I'm going to read that and see. – vtortola Sep 03 '12 at 09:19
  • 1
    If you feel that this is more of a *reporting* screen than a regular screen, then you don't have to put the querying logic in the domain layer. It can live alongside the main DDD architecture, in a dedicated reporting module. See http://stackoverflow.com/questions/7831763/ddd-reporting-scenarios – guillaume31 Sep 03 '12 at 11:34
  • I see. That is sound, and I'm happy with your answer and the provided links, but I'm going to raise a bounty for this question, since I think more people has been in this situation. Thanks! – vtortola Sep 03 '12 at 13:34
  • 1
    +1. I agree that this is something for the User repository to provide. You are letting the persistence mechanism affect your domain model by creating a domain object to speed up queries. If you need to solve the multiple query problem, ask that in a separate question but don't change the domain model to satisfy technical implementations like databases or user interfaces. – Fenton Sep 04 '12 at 14:31
  • +1 for the answer as well as the comments -- this does sound like a reporting task, if not, a repository will work. – casablanca Sep 05 '12 at 04:56
0

I agree with guillaume31 that there is no need to introduce a domain object "UsersPerPermission" to support a single use case.

There are two ways you can implement your use case using existing domain classes "User", "Role" and "Permission".


Solution one:

Assume you have: Permission --> Role --> User

Arrow denotes navigability. A Permission has association to a list of Roles and a Role has association to a list of Users.

I would add a method GetPermittedUsers() : List<User> to the Permission class, which is trivial to implement.

Th UI logic will invoke GetPermissions() of PermissionRepository then call GetPermittedUsers() on each Permission.

I assume that you use a ORM framework like hibernate(Nhibernate) and defines the many-to-many relationships correctly. If you defines eager loading for Role and User from Permission, the ORM will generate a query that joins Permission, Role and User tables together and load everything in one go. If you defines lazy loading for Role and User, you will load a list of Permissions in one query when you call PermissionRepository, and then load all associated Roles and Users in another query. Everything is load from database with up to three queries maximum. This is called a 1+n problem which most ORMs handle properly.


Solution two:

Assume you have: User --> Role --> Permission

Arrow denotes navigability. A User has a list of Roles. A role has a list of Permission.

I'd add getUsersByPermissions(List<long> permissionIds) : List<Users> to the UserRepository, and add getPermissions() : List<Permission> to the User class.

The implementation of the UserRepository need to join the User, Role and Permission tables together in a single query and load everything in one go. Again, most ORMs will handle it correctly.

Once you have a list of Users, you can create a method to build a Map<Permission, List<User>> quite easily.


To be honest, I muck like the solution one. I avoid to write a complicate method to convert a List of Users to to a map of Permission and Users, hence I don't need to worry about where to put this method. However solution one may create cyclic relationship between User, Role and Permission classes if you already have navigability in another direction. Some people don't like cyclic relationship. I think the cyclic relationship is acceptable even necessary sometime if you user cases demand it.

nwang0
  • 750
  • 5
  • 7
0

In a similar context I used a query method in a domain service that returns something like an

IEnumerable<KeyValuePair<PermissionName, IEnumerable<Username>>>

By using the KeyValuePair<> I avoided to pollute the domain model with an artificial concept (like UsersPerPermition). Moreover such a structure is immutable. I didn't used a query method on the repository because, in my context, no entity was coupled with the other. So it wasn't matter for any of the repositories.

However this solution is useful for your GUI, if and only if you modelled correctly the identifiers of your entities (in your example both Permissions and Users are entities). Indeed if they are shared identifiers that belong to the ubiquitous language that your users understand, they will be enough without further descriptions.

Otherwise you are just building a useful DTO for your GUI. It does not belong to the domain thus you should use the simplest possible thing that works (an ADO.NET query? something even simpler?). Indeed, in my own scenario both the GUI and the domain used such a service (the GUI showing a preview of an elaboration).

In general, the domain model must mirror the domain expert's language, capturing the knowledge relevant to the bounded context. Everything else must be outside the domain (but most of time can be expressed in terms of the domain's value objects).

Giacomo Tesio
  • 7,144
  • 3
  • 31
  • 48