3

We have our migrations, and we have a seed method that executes after every migration is run.

If the seed method fails, I can rollback the seed data but I also want to, in code, rollback the "update-database" statement to restore the db structure to what it was prior.

Is this possible?

Some code:

internal sealed class Configuration : DbMigrationsConfiguration<TheContext>
{
    protected override void Seed(TheContext context)
    {
        //Set a bunch of entities

        using (var transaction = new TransactionScope())
        {
            try
            {
                context.SaveChanges();
                transaction.Complete();
            }
            catch (Exception ex)
            {
                //TODO: How do I rollback the last Update-Database command?
                throw;
            }
    }
}
CaffGeek
  • 21,856
  • 17
  • 100
  • 184
  • According to the [TransactionScope](http://msdn.microsoft.com/en-us/library/system.transactions.transactionscope.complete.aspx) on MSDN, if you don't call .Complete(), the transaction will automatically rolled back. – zs2020 Jan 31 '13 at 15:04
  • The issue is, it's not THIS transaction I need to roll back, it's the `update-database` that was triggered in the Package Manager Console that I want to roll back – CaffGeek Jan 31 '13 at 15:11
  • Oh sorry, maybe [this](http://stackoverflow.com/questions/10282532/entity-framework-start-over-undo-rollback-all-migrations) helps. – zs2020 Jan 31 '13 at 15:19
  • @sza, it does, but it requires manual intervention. I would like to be able to automatically undo the last attempted migration if the seed fails. – CaffGeek Jan 31 '13 at 15:21

1 Answers1

0

My recommendation on cases like yours, that you have data that affects the migration success, is to do it inside the migration.

I do it all the time, creating sql scripts to be runned inside the migration's Up method, and down method. That way when the migration applies succesfully you know it is consistent with the data also. Plus, you can undo the migration, undoing at the same time all the data.

The downside of this approach is that you can't use EF's context to create data, forcing you to create Sql methods that run your hand-crafted sentences.

public class TestMigration() : DbMigration
{
    protected override Up() 
    {
       //Do some migration stuff

       Sql("INSERT YOUR DATA HERE");
    }

    protected override Down() 
    {
      //Undo some migration stuff
      Sql("DELETE YOUR DATA HERE");
    }   
}

If you still want to go with the Seed method aprroach, I didn't try it by myself, but I think this could work:

internal sealed class Configuration : DbMigrationsConfiguration<TheContext>
{
    protected override void Seed(TheContext context)
    {
        //Set a bunch of entities

        using (var transaction = new TransactionScope())
        {
            try
            {
                context.SaveChanges();
                transaction.Complete();
            }
            catch (Exception ex)
            {
                var migrator = new DbMigrator(this);

                var lastMigration = migrator.GetDatabaseMigrations().Last();

                migrator.Update(lastMigration);
            }
    }
}

The problem I can see with this code is that, after running the Update method, the Seed method will trigger again, creating an infinite loop.

Iñaki Elcoro
  • 2,153
  • 1
  • 18
  • 33