Search code examples
c#entity-frameworkef-code-firstmany-to-manyef-code-first-mapping

How to solve Code First from database many-to-many mapping in Entity Framework?


Bellow code snippet showing my scenario:

[Table("User")]
public partial class UserModel
{
 public UserModel()
 {
    UserRole = new HashSet<UserRoleModel>();
 }

  public int UserID { get; set; }
  public string FullName { get; set; }
  public virtual ICollection<UserRoleModel> UserRole { get; set; }
}

[Table("UserRole")]
public partial class UserRoleModel
{
    public UserRoleModel()
    {
            User = new HashSet<UserModel>();
    }

   public int RoleID { get; set; }
   public string RoleName { get; set; }
   public virtual ICollection<UserModel> User { get; set; }

}

Now within OnModelCreating(DbModelBuilder modelBuilder) EF Generate code like bellow

modelBuilder.Entity<UserModel>()
                .HasMany(e => e.UserRole)
                .WithMany(e => e.User)
                .Map(m => m.ToTable("UserRoleMapping").MapLeftKey("UserID").MapRightKey("UserRoleID"));

now this is fine add / insert data into UserRoleMapping table. But how to

Get / Update data from UserRoleMapping table ?

I try to solve this issue following create-code-first-many-to-many the post and come-up with third class with join entity

 public partial class UserRoleMappingModel
    {
        [Key, Column(Order = 0)]
        public Guid UserId { get; set; }
        public UserModel User { get; set; }

        [Key, Column(Order = 1)]
        public int RoleId { get; set; }
        public UserRoleModel UserRole { get; set; }
    }

then add public virtual ICollection<UserRoleMappingModel> UserRoleMapping { get; set; } in both the UserModel and UserRoleModel class

But when I try to GET value from database using bellow code

var results = _userRepository.GetAll()
                 .Include(r => r.UserRoleMapping
                 .Select(s => s.UserRole))
                 .SingleOrDefault(e => e.ID == id); 

It throws ERROR

"An error occurred while executing the command definition. See the inner exception for details.System.Data.SqlClient.SqlException (0x80131904): Invalid object name 'dbo.UserRoleMappingModel'.\r\n

Even I tried bellow Configuration within OnModelCreating, but nothing work as expected

modelBuilder.Entity<UserRoleMappingModel>()
 .HasKey(e => new { e.UserId, e.RoleId });

Solution

  • AS per GertArnold response I solve the issue in bellow way.

    1st Remove below settings

    modelBuilder.Entity<UserModel>()
                    .HasMany(e => e.UserRole)
                    .WithMany(e => e.User)
                    .Map(m => m.ToTable("UserRoleMapping").MapLeftKey("UserID").MapRightKey("UserRoleID"));
    

    2nd Add bellow settings

    modelBuilder.Entity<UserRoleMappingModel>()
     .HasKey(e => new { e.UserId, e.RoleId });
    

    3rd add table property in Mapping Model

    [Table("UserRoleMapping")]
    public partial class UserRoleMappingModel
        {
            [Key, Column(Order = 0)]
            public Guid UserId { get; set; }
            public UserModel User { get; set; }
    
            [Key, Column(Order = 1)]
            public int RoleId { get; set; }
            public UserRoleModel UserRole { get; set; }
        }
    

    4th Create a Mapping Repository

    IUserRoleMappingRepository
    

    5th a simple get Method (Problem Solved)

    var results = _userRoleMappingRepository.SearchFor(e => e.UserId == id)
                                                                .Select(s => new
                                                                {
                                                                    s.UserId,
                                                                    s.UserRoleId,
                                                                    s.UserRole.RoleName
                                                                })
                                                               .FirstOrDefault();
    

    Point to be noted : using bellow query I able to get result but unable to serialize with Newtonsoft.Json due to self referencing issue

    var results = _userRepository.GetAll()
                     .Include(r => r.UserRoleMapping
                     .Select(s => s.UserRole))
                     .SingleOrDefault(e => e.ID == id); 
    

    Try bellow JsonSerializerSettingssetting alternatively but unable to serialize sucessfully

    PreserveReferencesHandling = PreserveReferencesHandling.All / Object
    ReferenceLoopHandling = ReferenceLoopHandling.Serialize / Ignore