Search code examples
c#.netentity-frameworkentity-framework-corecode-first

What does Add-Migration command use to compare schemas?


I'm renaming several tables and columns. Since I don't want to lose the existing data, I created a migration from scratch.

protected override void Up(MigrationBuilder migrationBuilder)
{
    migrationBuilder.RenameTable(name: "Providers", schema: "dbo", newName: "Vendors", newSchema: "dbo");
    migrationBuilder.RenameTable(name: "ProviderContacts", schema: "dbo", newName: "VendorContacts", newSchema: "dbo");
    migrationBuilder.RenameColumn(name: "ProviderId", table: "AspNetUsers", newName: "VendorId", schema: "dbo");
    migrationBuilder.RenameColumn(name: "ProviderId", table: "VendorContacts", newName: "VendorId", schema: "dbo");
    migrationBuilder.RenameColumn(name: "ProviderId", table: "Locations", newName: "VendorId", schema: "dbo");
}

I then ran Update-Database. But this still leaves a bunch of indexes and foreign keys that should also be renamed. So I used the Add-Migration command to bring any remaining changes up to date.

But I notice the new migration seems to be dropping and recreating tables and columns that my custom migration already renamed.

migrationBuilder.DropTable(
    name: "ProviderContacts");

migrationBuilder.DropTable(
    name: "Providers");

migrationBuilder.DropIndex(
    name: "IX_Locations_ProviderId",
    table: "Locations");

migrationBuilder.DropIndex(
    name: "IX_AspNetUsers_ProviderId",
    table: "AspNetUsers");

migrationBuilder.DropColumn(
    name: "ProviderId",
    table: "Locations");

migrationBuilder.DropColumn(
    name: "ProviderId",
    table: "AspNetUsers");

My question is: What is the Add-Migration command comparing? Is it looking at the database or something else? Why didn't it recognize that these tables and columns have been renamed?

How can I get it to recognize the changes in my custom migration?


Solution

  • In EF Core, Update-Database uses the IMigrationsAssembly service to discover migrations compiled into your assembly. It fetches the list of migrations that have been run against this database using another service. As the migrations are executed the list of migrations are updated in a table. The process doesn't know or care about the state of your database model, it doesn't cause any change in your database model. The process is designed to work against other databases, without any knowledge of your development environment.

    Running Add-Migration uses the IMigrationsAssembly service to load the previous ModelSnapshot that has been compiled into your assembly, and the model from your contexts OnModelCreating method. Then it uses the IMigrationsModelDiffer service twice to compare the two models and produce the Up and Down migration routines. The new migration and ModelSnapshot is then serialised back into source code and written to disk. This process knows nothing about the state of any database, or the list of operations in previous migrations.

    In other words, Add-Migration doesn't care that you've written another migration. It's still going to compare these two models. The migration differ isn't perfect, if the before and after tables are too different it will generate drop & create steps.

    Another option is to perform one change at a time, creating new migrations for each step. Then merge the Up & Down methods into the last migration. And delete the rest.