Search code examples
asp.net-mvcasp.net-identityasp.net-identity-2user-roles

Assigning a role to a user in extended Asp.Net Identity 2 error Violation of PRIMARY KEY constraint 'PK_dbo.AspNetUserRoles'


I have extended AspNetUserRoles for my application where I have added a new FK column ApplicationId in AspNetUserRoles table. The idea behind this is to allow same user to be in different applications with same or different roles. Everything seems Ok till I tried to add the same role to the same user but for a different application where I have started getting the error:

Violation of PRIMARY KEY constraint 'PK_dbo.AspNetUserRoles'. Cannot insert duplicate key in object 'dbo.AspNetUserRoles'.

Could please anyone help me to come out of this problem.

my IdenitityModels is as follow

 public class ApplicationUser : IdentityUser
{
    public virtual AspNetApplications AspNetApplication { get; set; }
    public virtual AspNetUserRoles AspNetUserRoles { get; set; }

    public async Task<ClaimsIdentity> GenerateUserIdentityAsync(UserManager<ApplicationUser> manager)
    {
        var userIdentity = await manager.CreateIdentityAsync(this, DefaultAuthenticationTypes.ApplicationCookie);
        return userIdentity;
    }
}

public class ApplicationDbContext : IdentityDbContext<ApplicationUser>
{
    public ApplicationDbContext()
        : base("DefaultConnection", throwIfV1Schema: false)
    {
    }

    public static ApplicationDbContext Create()
    {
        return new ApplicationDbContext();
    }

    public DbSet<AspNetApplications> AspNetApplications { get; set; }
    public DbSet<AspNetUserRoles> AspNetUserRoles { get; set; }

    protected override void OnModelCreating(DbModelBuilder modelBuilder)
    {
        base.OnModelCreating(modelBuilder);
    }

}

My AspNetApplications and AspNetUserRoles models are as follow

public class AspNetApplications
{
    [Key]
    public string ApplicationId { get; set; }
    public string ApplicationName { get; set; }
}

public class AspNetUserRoles : IdentityUserRole
{
    [Key]
    public string ApplicationId { get; set; }

    [ForeignKey("ApplicationId")]
    public AspNetApplications AspNetApplications { get; set; }
}

Following is the code where I am adding a new entity of type AspNetUserRoles and it throws the error at dbContext.SaveChanges()

            var aspNetUserRole = new AspNetUserRoles
            {
                UserId = userId,
                RoleId = roleId,
                ApplicationId = applicationId,
            };

            dbContext.AspNetUserRoles.Add(aspNetUserRole);
            dbContext.SaveChanges();

Solution

  • IdentityUserRole implements a composite foreign key consistent of UserId and RoleId. Your subclass only has a key set for ApplicationId, so one of two things is happening:

    1. The key is ApplicationId, in which case only one user role could ever be added for any given application.
    2. The key is UserId and RoleId, and since it's the same user and same role, you're violating the constraint.

    Essentially, you need to ensure that the composite key consists of UserId, RoleId, and ApplicationId. Since you can't control the base implementation of IdentityUserRole, the best way to ensure that would be to use fluent config. Add the following to your context class.

    protected override void OnModelCreating(DbModelBuilder modelBuilder)
    {
        modelBuilder.Entity<AspNetUserRoles>().HasKey(m => new { m.ApplicationId, m.UserId, m.RoleId });
    }
    

    Also, FWIW, you don't need to name your classes AspNet*. If you want the same table names, just decorate the class with [Table("AspNetUserRoles")].