Facing issue with Entity framework Db approach

Viewed 20

I have these classes

public class UserRole
{
      public int RoleId { get; set; }
      public int UserId { get; set: }
      public virtual User User { get; set; }
      public virtual Role Role { get; set; }
}

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

    public int FirstName { get; set; }
    public int UserId { get; set: }

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

[Table("Role")]
public class Role
{
    public Role()
    { 
        UserRoles = new HashSet<UserRole>();
    }

    public int RoleId { get; set; }
    public string RoleName { get; set; }

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

I am trying to do simple insert into the UserRole table

public class Run
{
   DbContext context;

   public Run()
   {
       context = new DbContext();
   }

   public void Validate(User user, int roleId)
   { 
       InsertUserRole(user,roleId)
       context.SaveChanges();
   }
}
   
public void InsertUserRole(user targetUser, int roleId)
{
    UserRole targetUserRole = targetUser.UserRoles
                                        .Where(u => u.RoleId == roleId)
                                        .FirstOrDefault();

    if (targetUserRole == null)
    {
        targetUserRole = new UserRole();
        targetUserRole.RoleId = roleId;
        targetUserRole.UserId = targetUser.UserId;

        context.UserRoles.Add(targetUserRole);
    }
}

When I am trying to insert into UserRole table, I get an exception

Violation of Unique KEy 'UQ_Role_Name'.Cannot insert duplicate key in dbo.Role

I need to insert row into UserRole as the role does not exist for user, and the role is present in Role table.

Please let me know how I can insert into Userole table using Entity Framework context

1 Answers

I'm not sure if there is enough info about your entities/schema to narrow down the specific cause of your issue, but a few things do come to mind.

Firstly, how are you nominating the PK for the UserRole entity? This should either be done with attributes in the entity or via entity configuration:

public class UserRole
{
    [Key, Column(Order=0), ForeignKey("User")]
    public int UserId { get; set; }
    [Key, Column(Order=1), ForeignKey("Role")]
    public int RoleId { get; set; }

    public virtual User User { get; set; }
    public virtual Role Role { get; set; }
}

Next, to add a new UserRole it should be possible to do so by setting the IDs, though generally I recommend setting the navigation properties rather than the IDs. The reasons for this is that this validates the values you are passing, and the entity should be considered "complete" (navigation properties are available) after saving.

For your InsertUserRole method, there are a couple of adjustments there. You don't need to load the existing entity, a simple exists check would be sufficient and faster, then loading the relevant references. This can either be inserted to a UserRole DBSet, or added to the requested user:

public void InsertUserRole(int userId, int roleId)
{
    var userRoleExists = context.UserRoles.Any(x => x.UserId == userId && x.RoleId == roleId);

    if(userRoleExists) return;

    var user = context.Users.Single(x => x.UserId == userId);
    var role = context.Roles.Single(x => x.RoleId == roleId);

    UserRole userRole = new UserRole
    {
        User = user,
        Role = role
    };
    context.UserRoles.Add(userRole);
    context.SaveChanges();
}

or alternatively:

public void InsertUserRole(int userId, int roleId)
{
    var user = context.Users
        .Include(x => x.UserRoles)
        .Single(x => x.UserId == userId);

    if(user.UserRoles.Any(x => x.RoleId == roleId) return;

    var role = context.Roles.Single(x => x.RoleId == roleId);

    UserRole userRole = new UserRole
    {
        User = user,
        Role = role
    };
    user.UserRoles.Add(userRole);
    context.SaveChanges();
}
Related