Ef core many to many relationship inside a generic repository

c# entity-framework-core

Question

I am trying to get work with many-to-many relationship in my web application. I am using a generic repository base code.

Here my the entities

public class UserEntity : BaseEntity<int>
{
    public string EmployeeId { get; set; }
    public string FullName { get; set; }
    public string Email { get; set; }

    public virtual ICollection<UserRoleEntity> UserRoles { get; set; }
}

public class RoleEntity : BaseEntity<int>
{
    public string Name { get; set; }

    public virtual ICollection<UserRoleEntity> Users { get; set; }
}

public class UserRoleEntity : BaseEntity<Guid>
{
    public int UserId { get; set; }
    public int RoleId { get; set; }

    public virtual UserEntity UserEntity { get; set; }
    public virtual RoleEntity RoleEntity { get; set; }
}

This is context model configuration

private void ConfigureUserRole(EntityTypeBuilder<UserRoleEntity> builder)
{
    builder.ToTable("UserRole");

    //there is no need for a surrogate key on many-to-many mapping table
    builder.Ignore("Id");

    builder.HasKey(ur => new { ur.RoleId, ur.UserId });

    builder.HasOne(ur => ur.RoleEntity)
        .WithMany(r => r.Users)
        .HasForeignKey(ur => ur.RoleId);

    builder.HasOne(ur => ur.UserEntity)
        .WithMany(u => u.UserRoles)
        .HasForeignKey(ur => ur.UserId);
}

This is the main get method of my generic repository (in fact it is Chris Pratt's implementation) Please notice the query.Include line, the get methods of generic repository make use of EF Core's Include api to get dependent entity which comes as string parameter .

 protected virtual IQueryable<T> GetQueryable(Expression<Func<T, bool>> filter = null, Func<IQueryable<T>, IOrderedQueryable<T>> orderBy = null,
                                                    string includeProperties = null,
                                                    int? skip = null,
                                                    int? take = null)
        {
            includeProperties = includeProperties ?? string.Empty;
            IQueryable<T> query = _dbContext.Set<T>();

            if (filter != null)
            {
                query = query.Where(filter);
            }

            foreach (var includeProperty in includeProperties.Split
                (new char[] { ',' }, StringSplitOptions.RemoveEmptyEntries))
            {
                query = query.Include(includeProperty);
            }

            if (orderBy != null)
            {
                query = orderBy(query);
            }

            if (skip.HasValue)
            {
                query = query.Skip(skip.Value);
            }

            if (take.HasValue)
            {
                query = query.Take(take.Value);
            }

            return query;
        }

And in my service, I want to get user data with its full dependents.

public class UserService : IUserService
{
    private IRepository<UserEntity> _userRepository;
    private IRepository<RoleEntity> _roleRepository;

    public UserService(IRepository<UserEntity> userRepository, IRepository<RoleEntity> roleRepository)
    {
        _userRepository = userRepository;
        _roleRepository = roleRepository;
    }
    public UserEntity GetUserData(string employeeId)
    {
        var user = _userRepository.GetFirst(u => u.EmployeeId == employeeId, includeProperties: "UserRoles");
        //var roles = _roleRepository.GetAll().ToList();

        return user;
    }
}

When the above service code executed, I get the user with its UserRole dependent, however, when I inspect UserRole's RoleEntity dependent which I need, it is null.

  • How can I get the dependent RoleEntity data just modifying the generic repository's get method?

  • Secondly, the line commented in service code (_roleRepository.GetAll()), when it is also executed, the RoleEntity is immediately filled with its proper value. How is it happening?

1
1
10/31/2018 2:11:47 PM

Accepted Answer

Your include path only has a single hop from UserEntity to UserRoleEntity (via the UserRoles property. You need to include the next step to ensure you also capture the RoleEntity. To do this, change your path to UserRoles.RoleEntity, for example:

var user = _userRepository.GetFirst(
    u => u.EmployeeId == employeeId, 
    includeProperties: "UserRoles.RoleEntity");
1
10/31/2018 2:31:55 PM


Related Questions





Related

Licensed under: CC-BY-SA with attribution
Not affiliated with Stack Overflow
Licensed under: CC-BY-SA with attribution
Not affiliated with Stack Overflow