Renaming Identity tables with EF6 Migrations Failing
OnModelCreating
is the place to do it, but you also want to leverage migrations for this kind of thing. Having said that, assuming we add the changes to our "ApplicationDbContext" (using default project names) within OnModelCreating
:
protected override void OnModelCreating(DbModelBuilder modelBuilder)
{
base.OnModelCreating(modelBuilder);
modelBuilder.Entity<ApplicationUser>().ToTable("Users");
modelBuilder.Entity<IdentityRole>().ToTable("Roles");
modelBuilder.Entity<IdentityUserClaim>().ToTable("UserClaims");
modelBuilder.Entity<IdentityUserLogin>().ToTable("UserLogins");
modelBuilder.Entity<IdentityUserRole>().ToTable("UserRoles");
}
Calling Add-Migration AspNetIdentity_RenameTables
should generate our migration script for us (this assumes an existing migration exists to create the identity tables using the default naming):
public partial class AspNetIdentity_RenameTables : DbMigration
{
public override void Up()
{
RenameTable(name: "dbo.AspNetRoles", newName: "Roles");
RenameTable(name: "dbo.AspNetUserRoles", newName: "UserRoles");
RenameTable(name: "dbo.AspNetUsers", newName: "Users");
RenameTable(name: "dbo.AspNetUserClaims", newName: "UserClaims");
RenameTable(name: "dbo.AspNetUserLogins", newName: "UserLogins");
}
public override void Down()
{
RenameTable(name: "dbo.UserLogins", newName: "AspNetUserLogins");
RenameTable(name: "dbo.UserClaims", newName: "AspNetUserClaims");
RenameTable(name: "dbo.Users", newName: "AspNetUsers");
RenameTable(name: "dbo.UserRoles", newName: "AspNetUserRoles");
RenameTable(name: "dbo.Roles", newName: "AspNetRoles");
}
}
Now calling Update-Database
takes care of the rest. Obviously, if you had setup your DbInitializer using the Migrate initializer, this would be done for you on first load).
Now, we have the renamed tables:
An example (with commit history) can be found on GitHub: https://github.com/bchristie/AspNetIdentity-RenameTables
To add some clarity:
OnModelCreating
has its purpose, and that's to let EF know of relationships, keys, entity-to-table relationships, etc. The Migrations feature of EF works exceptionally well at taking it a step further and managing the in-between states of the database, so I like to leverage it whenever possible.
Given the IdentityDbContext has its own declarations within, we need to trump its configuration by adding an OnModelCreating
of our own (but only after we've called the base method). Now we have all the existing structure, but with a new name.
It's also important to reference the entities you're working with. So, since the default project uses an ApplicationUser
, this is what we'd reference in modelBuilder.Entity<>()
.
If you read the comments above, this is more of a work around than an actual solution.
First (and not related to the error above), part of the code to rename my AspNetUsers table was missing and therefore, so was a necessary line from my onModelCreating
function:
protected override void OnModelCreating(DbModelBuilder modelBuilder)
{
base.OnModelCreating(modelBuilder);
modelBuilder.Entity<IdentityUser>().ToTable("Users");
modelBuilder.Entity<ApplicationUser>().ToTable("Users"); //this line needed!!
modelBuilder.Entity<IdentityRole>().ToTable("Roles");
modelBuilder.Entity<IdentityUserRole>().ToTable("UserRoles");
modelBuilder.Entity<IdentityUserLogin>().ToTable("UserLogins");
modelBuilder.Entity<IdentityUserClaim>().ToTable("UserClaims");
}
Even after correcting that, the necessary migrations code was being generated with the SQL code in the wrong order and still throwing the error above, referencing the old table names after the table had already been renamed. So, I had to edit the migration file directly and move the DropForeignKey
methods to the top ahead of RenameTable
methods:
public override void Up()
{
DropForeignKey("dbo.AspNetUserClaims", "UserId", "dbo.AspNetUsers");
DropForeignKey("dbo.AspNetUserLogins", "UserId", "dbo.AspNetUsers");
DropForeignKey("dbo.AspNetUserRoles", "UserId", "dbo.AspNetUsers");
RenameTable(name: "dbo.AspNetRoles", newName: "Roles");
RenameTable(name: "dbo.AspNetUserRoles", newName: "UserRoles");
RenameTable(name: "dbo.AspNetUsers", newName: "Users");
RenameTable(name: "dbo.AspNetUserClaims", newName: "UserClaims");
RenameTable(name: "dbo.AspNetUserLogins", newName: "UserLogins");
DropIndex("dbo.UserRoles", new[] { "UserId" });
DropIndex("dbo.UserClaims", new[] { "UserId" });
DropIndex("dbo.UserLogins", new[] { "UserId" });
AddColumn("dbo.UserRoles", "IdentityUser_Id", c => c.String(maxLength: 128));
AddColumn("dbo.Users", "Discriminator", c => c.String(nullable: false, maxLength: 128));
AddColumn("dbo.UserClaims", "IdentityUser_Id", c => c.String(maxLength: 128));
AddColumn("dbo.UserLogins", "IdentityUser_Id", c => c.String(maxLength: 128));
AlterColumn("dbo.UserClaims", "UserId", c => c.String());
CreateIndex("dbo.UserRoles", "IdentityUser_Id");
CreateIndex("dbo.UserClaims", "IdentityUser_Id");
CreateIndex("dbo.UserLogins", "IdentityUser_Id");
AddForeignKey("dbo.UserClaims", "IdentityUser_Id", "dbo.Users", "Id");
AddForeignKey("dbo.UserLogins", "IdentityUser_Id", "dbo.Users", "Id");
AddForeignKey("dbo.UserRoles", "IdentityUser_Id", "dbo.Users", "Id");
}
Upon changing that Update-Database
ran successfully.
I watched a video tutorial of this process on www.asp.net/identity and read several google leads on it and I don't really know why mine is erroring and the examples are not. I guess I'm lucky. But, here is my environment, just in case it's a bug:
- MVC 5.2.3
- EF 6.1.3
- Identity 2.2.1
- VS 2013
- SQL Express 2014
On to the next issue... see you guys soon...