Context
I am building a multi-tenant sass app with asp.net core identity and ef core. I discovered what I think is an issue when you attempt to 'override' the primary key on an entity. I am extending the IdentityUserRole entity to add a tenant id and then adding a new primary key with TenantId, UserId and RoleId. The problem is that the old primary key becomes an alternate key and adds a unique constraint between RoleId and UserId.
My expectation is that setting a new primary key should replace the existing one that was configured. If I want the old one as an alternate key then I should explicitly set it.
Code
IdentityDbContext OnModelCreating
builder.Entity<TUserRole>(b =>
{
b.HasKey(r => new { r.UserId, r.RoleId });
b.ToTable("AspNetUserRoles");
});
My DbContext OnModelCreating
base.OnModelCreating(builder);
builder.Entity<UserRole>(b => {
b.ToTable("UserRoles");
b.HasKey(e => new { e.TenantId, e.UserId, e.RoleId });
b.HasOne<Tenant>().WithMany().HasForeignKey(e => e.TenantId);
});
Migration Created
migrationBuilder.CreateTable(
name: "UserRoles",
columns: table => new
{
TenantId = table.Column<int>(nullable: false),
UserId = table.Column<int>(nullable: false),
RoleId = table.Column<int>(nullable: false)
},
constraints: table =>
{
table.PrimaryKey("PK_UserRoles", x => new { x.TenantId, x.UserId, x.RoleId });
table.UniqueConstraint("AK_UserRoles_UserId_RoleId", x => new { x.UserId, x.RoleId });
table.ForeignKey(
name: "FK_UserRoles_Roles_RoleId",
column: x => x.RoleId,
principalTable: "Roles",
principalColumn: "Id",
onDelete: ReferentialAction.Cascade);
table.ForeignKey(
name: "FK_UserRoles_Tenants_TenantId",
column: x => x.TenantId,
principalTable: "Tenants",
principalColumn: "Id",
onDelete: ReferentialAction.Cascade);
table.ForeignKey(
name: "FK_UserRoles_Users_UserId",
column: x => x.UserId,
principalTable: "Users",
principalColumn: "Id",
onDelete: ReferentialAction.Cascade);
});
This issue is in EF Core 2.0.1
Questions
Is if there is a way to remove the old primary key constraint when configuring the new one?
If not, what are my best options for a work around?
I ended up fixing this issue by having my context extend IdentityUserContext instead of IdentityDbContext and copying the code from IdentityDbContext into mine. I also had to change the implementation of UserClaimsPrincipalFactory for aspnet identity but I think that is only because I extended IdentityUserRole.
In this case it was pretty straight forward but I do think I shouldn't have to do this. Overriding a primary key should be the same as overriding a table name.
@andrewalderson The simple answer is that when a primary key is changed, then, any relationships with foreign keys that reference that key also need to be updated. The longer answer is that we need better documentation in this area, which is on my backlog to do and is tracked here: https://github.com/aspnet/Identity/issues/1542
Most helpful comment
I ended up fixing this issue by having my context extend IdentityUserContext instead of IdentityDbContext and copying the code from IdentityDbContext into mine. I also had to change the implementation of UserClaimsPrincipalFactory for aspnet identity but I think that is only because I extended IdentityUserRole.
In this case it was pretty straight forward but I do think I shouldn't have to do this. Overriding a primary key should be the same as overriding a table name.