Home > Net >  Can I create a repository for a joining entity (entity framework)
Can I create a repository for a joining entity (entity framework)

Time:12-06

I want to get all users with their roles and display them in a DatGrid (react). Thus, I must have a list and each item must contains a user with one role.

Here is an example of a list I would like to have:

[ { idUser : 1, NameUser : "Martin", IdRole : 1 NameRole, "Admin" } { idUser : 1, NameUser : "Martin", IdRole : 2 NameRole, "Agent" } { idUser : 2, NameUser : "Jullien", IdRole : 1 NameRole, "Admin" } ]

My question is does it make sense to have a repository for the UserRole entity knowing that this entity is not an aggregate ?

Class Diagram

CodePudding user response:

In your model example, you don't even need a UserRole entity. (Unless sticking with EF Core <= 2) Many-to-Many relationships that only require a joining table with the two FKs as a composite key can be auto-mapped so that User can have a collection of Roles, while Role has a collection of Users. EF can be configured to map the relationship behind the scenes with a UserRole table. The only time you would need to consider a UserRole entity would be if there are additional attributes to track about the user to role association. An example of that would be if you have a soft-delete system with something like an IsActive flag and want the relationships between users and roles to be soft-delete-able.

Regarding the association of Repositories and entities: IMHO the Generic Repository, or Repository per Entity approach with EF is an anti-pattern. The EF DbContext and DbSets perform the function of a Unit of Work and Repository and afford a lot more flexibility than the typical Repository pattern that gets implemented to try and abstract them. Repositories do serve as an excellent boundary for Unit Testing, though I highly recommend designing repositories to serve the Controllers, Presenters, or Services rather than per-Entity. For example, if you have a ManageUserController, then design for a ManageUserRepository that is responsible for providing all entities and encapsulating the domain functionality for that business logic. The alternative is to have a reference to a UserRepository and a RoleRepository and who knows how many other Repositories. The Generic repository pattern is popular because it is interpreted as obeying SRP (Single Responsibility Principal) being that it is responsible for access to one entity. However, I would counter-argue that it violates SRP because when you try and reuse a Repository across multiple concerns (Controllers etc.) you give that repository many reasons it may need to change. To avoid that, you either have an aenemic repository that does nothing but expose a DbSet, or you have to restrict all access to the data down to the lowest common denominator. This limits flexibility and opens the door for performance issues and unintended behaviour. A Repository targeted at a business consumer has one, and only one reason to change. It also makes the dependency graph a LOT simpler without needing to resolve many repositories for each Controller/Service.

For truly common, shared behaviour, a purpose-built Repository can be referenced by consumers or by the purpose-driven Repositories. (I.e. a LoggingRepository or LookupRepository)

Edit: Based on the comment to get data for each user and role combination:

var data = _dbContext.Users
    .SelectMany(u => u.Roles
        .Select(r => new {IdUser = u.Id, NameUser = u.Name, IdRole = r.Id, NameRole = r.Name }))
    .ToList();

This should populate the desired structure. To serialize you could declare a DTO class with those properties and populate it instead of the anonymous type.

One key aspect of building efficient queries around EF is Projecting data into desired outputs rather than just expecting to output and transmit entities. This can result in faster queries using less memory and bandwidth to get just the data you need in the format you need it.

  • Related