Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How can I stop Add-Migration checking my database has no pending migrations when using Code-Based migrations?

I'm investigating using Code-Based EF Migrations for a product that does not use EF. Everything generally works well, except that the command:

Add-Migration MyTestMigration

outputs the following message:

Unable to generate an explicit migration because the following explicit migrations are pending: [201206260845338_DannyTest]. Apply the pending explicit migrations before attempting to generate a new explicit migration.

The reason for this is that the connection string is not known at build time, and EF has randomly created a database called "MyContextName" on .\SQLExpress. I cannot apply the pending migration, because it references database tables that do not exist in this database - we're just trying to use migrations as a way of executing our scripts;

So the questions are:

  1. If we're not using Automatic Migrations (we have EnableAutomaticMigrations=false), why does Add-Migration require that the database is up-to-date even though it has absolutely no impact on the generated (empty) migration? I find it hard to believe MS don't intend this use case when so much of it works; the only "broken" thing is validation that doesn't affect any behaviour.

  2. Is there any way around this other than creating our own Add-Migration command that just duplicates what the EF one does, but skips the (seemingly needless) DB up-to-date check? I've tried passing various arguments, but so far not managed to make it work.

Edit:

I actually found a better way to solve this problem, but it's not really an answer to these questions, so adding it here. Hopefully will get time to turn this into a blog post!

The only reason I wanted to use Add-Migration was because of all the guff that went along with the DbMigration; but I realised that with a base class, we could basically eliminate the need for all this by having the base class auto-generate the migration ID from an attribute. The Target is identical for all our migrations, as the model state doesn't change. Now, we just manually create our migrations like this (the date is required to build the ID such that EF will apply them in the correct order):

[Migration(2012, 6, 27, 12, 00, "Add new xxx fields for yyy")]
internal class MyNewMigration : MyDbMigration
{
    public override Up()
    {
        // ...
    }
    public override Down()
    {
        // ...
    }
}

The MyDbMigration class has the Target/Source/Id properties. Target is hard-coded (the same value that Add-Migration created with the first migration), Source is null, and Id is some reflection that reads the MigrationAttribute. This means we can now just manually create these classes; which isn't a lot of effort now we don't have to worry about all the IMigrationMetadata stuff :-)

like image 563
Danny Tuppeny Avatar asked Jun 26 '12 09:06

Danny Tuppeny


1 Answers

Try commenting out your existing migrations (the ones that haven't been applied to the database created on .\SQLExpress) and re-running your app. That should populate the local database with the initial tables it needs.

Once the local database has the correct structure you should be able to uncomment your migrations and then use update-database to bring the local one up to date. Then you'll be able to add a new migration.

Also remember that there's a -connectionString parameter on the update-database command, so you can target your migrations at a specific server/db.

like image 146
Matt Hamilton Avatar answered Oct 11 '22 22:10

Matt Hamilton