Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Manually run Entity Framework migration Seed() method, including after Down() migration

Is there a simple way to manually run the Entity Framework migration Seed() method from the package-manager console, including after a Down() migration (Update-Database -TargetMigration foo)? The answer to "Run Code First Migration Seed Method without a migration" addresses how to manually run the Seed() method, which is to call Update-Database, but this doesn't work when the database is on an older migration and should not be updated. The same question was asked in "How to run Seed() method of Configuration class of migrations" but it was asked as part of a multi-part question, and this part remains unanswered (though the entire question is marked as answered now).

I'm asking because I have some cleanup code which needs to be run after a migration has been applied. Calling it from Seed() works fine for an Up() migration. I don't know how to easily call it for a Down() migration, though. I'd like a simple, one or two liner that would work from the package-manager. I know I could invoke the c# method after calling [Reflection.Assembly]::LoadFile() for all the necessary DLLs, but there are enough dependencies that this would be cumbersome and error prone.

I know that Seed() isn't an ideal place for Down() migration cleanup code (to add some context based on DrewJordan's answer), but using Down() itself is unfortunately non-viable for several reasons. From a practical standpoint, it is non-viable because the cleanup has to convert several gigabytes worth of data, and this caused SQL Server Express to crash when I tried a simple copy in Down(), probably because the resulting transaction size was enormous. Second, from even a hypothetical standpoint, I don't believe there is a way to convert the data to the extent needed in Down() because current SQL rows cannot be read in c# as part of the transaction, and the conversion of the data needs to take place in c#. For details on that limitation, see my other question: "Transform data using c# during Entity Framework migration". Some compromise of the design was needed to get the cleanup to work, and I was using Seed() as that compromise. The cleanup code doesn't need to be run from Seed() per se, but I don't know what else can be invoked from the package-manager without changing the current migration.

There is also another scenario where it would be useful to invoke Seed(), or other cleanup code, by itself without changing the current migration. Consider the scenario where there was a bug in the Seed()/cleanup method. You fix the bug and want to re-run it without changing the current migration. Putting the cleanup logic in Down() would not solve the problem because Down() won't be invoked when the database is already on that migration.

like image 692
twm Avatar asked Mar 05 '16 19:03

twm


1 Answers

I realize you asked about running it from the PM console: AFAIK it's not possible. This use case isn't what Seed is for: I would recommend if you have changes to make in a Down method, either write SQL scripts to run, or create a context in Down and do whatever there.

It's a bad idea because Seed counts on being up to date with the latest migration. It will allow you, for example, to write statements that can't possibly succeed on a prior version of your context, such as when a column is added to the model but not yet applied to the database. I haven't tried this but it'll throw an exception at the least, and possibly fail to write any changes.

If you really, really think this is a good idea, you can add a method into your configuration:

public void CallSeed()
{
    using (var c = new Context()) // create your context
    {
        Seed(c);
    }
}

And call it from Down:

var c = new Configuration();
c.CallSeed();
like image 131
DrewJordan Avatar answered Oct 25 '22 10:10

DrewJordan