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();
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:
ApplicationId
, in which case only one user role could ever be added for any given application.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")]
.