Update-Database fails due to Pending Changes, but Add-Migration Creates a Duplicate Migration

Nij picture Nij · Jul 29, 2013 · Viewed 10.2k times · Source

I'm working with Entity Framework 5.0 Code First Migrations, and am having a problem with running Update-Database. It says there are pending model changes; but it should be up-to-date, so I run

Add-Migration SomeMigrationName

and it creates a file... however, it creates a file which is essentially the same a duplicate of a prior Migration (if I try to Update-Database again on that file, it fails with issues related to trying to drop a non-existent constraint). Furthermore, I have been able to confirm that the 'original' migration has been run based on both the data model in the DB, and from the presence of a record in the __MigrationHistory table!

If I delete the whole database, and run all the migrations again, automatically or by hand, I have the same problem.

The 'original' migration file I had is as follows:

public partial class RenameLinkColumns : DbMigration
{
    public override void Up()
    {
        DropForeignKey("dbo.Listing", "OfferedByUserId", "dbo.User");
        DropIndex("dbo.Listing", new[] { "OfferedByUserId" });
        AddColumn("dbo.Listing", "ListedByUserId", c => c.Int(nullable: false));
        AddForeignKey("dbo.Listing", "ListedByUserId", "dbo.User", "UserId", cascadeDelete: true);
        CreateIndex("dbo.Listing", "ListedByUserId");
        DropColumn("dbo.Listing", "OfferedByUserId");
    }

    public override void Down()
    {
        AddColumn("dbo.Listing", "OfferedByUserId", c => c.Int(nullable: false));
        DropIndex("dbo.Listing", new[] { "ListedByUserId" });
        DropForeignKey("dbo.Listing", "ListedByUserId", "dbo.User");
        DropColumn("dbo.Listing", "ListedByUserId");
        CreateIndex("dbo.Listing", "OfferedByUserId");
        AddForeignKey("dbo.Listing", "OfferedByUserId", "dbo.User", "UserId", cascadeDelete: true);
    }
}

When I ran that Add-Migration again, the Up/Down methods in that file are exactly the same as these.

I'm quite impressed that migrations were correctly able to detect that I had renamed a ForeignKey column; but is that what is causing this to choke?

It seems there is a work-around: I have deleted the database, and all migration files, and created a new 'Initial' Migration, but I would prefer not to do this if possible.

Update: This was not the latest migration that caused this issue, but the problem started after a merge (I am working alone, but am simulating team work on branches to learn more about git too), and trying to get the database in step with the merge. Might this have come about from placing migrations in some particular order after a merge - though a noted, the migrations did work as expected in the order they ran when I gave them an empty DB.

Additionally, this original migration needed manually tweaking when the tables had data in, because data needed to be copied from the old to the new column. However, I tested that file with and without my manual edits in that file, and still encountered the behaviour noted.

Answer

Mike the Tike picture Mike the Tike · Jan 15, 2015

This answer explains why it happens. To resolve it I call add-migration and name it MERGE and then remove any duplicate migration code that has already happened. This is just to update the model snapshot to reflect the merged model.

Example:

public partial class MERGE : DbMigration
{
    public override void Up()
    {
        // Intentionally left blank.

        // This may seem like a hack, but it is necessary when using source control.
        // When a migration is created via add-migration, EF creates 
        // an .edmx file from the current code first classes. It compares this .edmx to the .edmx stored in the last migration before this, 
        // which I'll call it's parent migration. The edmx snapshots are gzipped and stored in base64 in the resource files (.resx) if you 
        // want to see them. EF uses the difference between these two snapshots to determine what needs to be migrated.

        // When using source control it will happen that two users add entities to the model independently. The generated edmx snapshots will 
        // only have the changes that they have made. When they merge in source control, they will end up with this:

        // Migration                        |  Snapshot Contents
        // -------------------------------- | ----------------
        // 20150101_Parent Migration        |  A
        // 20150102_Developer 1's Migration |  A + Change 1
        // 20150103_Developer 2's Migration |  A + Change 2

        // So calling add-migration will create the current snapshot edmx from the Code First model and compare it to the 
        // the latest migration's snapshot, which is A + Change 2, and see that Change 1 is missing. That is why it 
        // creates a duplicate migration. We know that the migrations have already been applied, so the only thing that this 
        // migration will do is update the current snapshot .edmx so that later migrations work fine.
    }

    public override void Down()
    {

    }
}