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

2

9

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 :-)

Dragoon answered 26/6, 2012 at 9:59 Comment(9)
I deleted my answer to give you chance for a "better answer".Modla
@Danny Tuppeny- If you can elaborate or find time to write that blog post, it would sure be appreciated.Rabblerouser
@AdrianCarr I didn't get chance to write it up; but the bottom half of the question has a lot of the details. We basically used Add-Migration to create the first migration, then made that into a base class (including the hard-coded Target from that first one) for the others (which look much like the one above). We named the classes as "_yyyyMMddmmhhss_descriptive_name".Dragoon
@AdrianCarr This works; because if migrations have the same Target, they are sorted by name (so our timestamp makes them run in the same order).Dragoon
However; this might only work, because our DbContext never actually changes - it's empty. We're currently using NHibernate, and the EF stuff is only for migrations.Dragoon
YMMV if you're actually using EF; as a hard-coded Target might not help :o(Dragoon
So; we're not actually using Add-Migration; we're just manually creating classes with Up/Down methods.Dragoon
Heh, it's a little ironic that your blog post link goes to the home page and not the post itself, from which I stumbled onto this post blog.dantup.com/2016/04/have-software-developers-given-up (which I do wholeheartedly agree with -- I'm exasperated at how everything is so damn broken)Sophronia
Yeah, the link said "hopefully"; I guess it never got turned into a post! Yeah, the state of software is not good, but a depressing number of devs seem ok with that :'(Dragoon
K
1

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.

Kindred answered 27/6, 2012 at 6:17 Comment(2)
It's crazy, but this might be the best solution. By removing the migrations, the DB won't have any pending migrations, and should create the new file. Hoping to get hold of someone on the EF team to see if they might be able to add a switch to just bypass this crazy restriction!Dragoon
Yep, this worked. Created an empty Up() method, commented out the real one, ran it, and now I can create the next migration.Rabblerouser
S
0

I was seeing this error until I deleted from the Solution the original auto-generated migration code that the Package Manager had initially created.

This would have been 201206260845338_DannyTest.cs in Danny's case.

Shayne answered 17/2, 2014 at 16:31 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.