The internets are eerily quiet when it comes to running Entity Framework's migrations through code, which is odd because Entity Framework's Code First migrations are extremely powerful and calling them (or rolling them back) through the code seems an obvious choice to someone like me, who prefers to reduce the amount of complexity for the poor IT people handling deployment.
(And for poor me, too, I'm very lazy and I like being able to just press a button to make magic happen.)
The most important quirk of running migrations programmatically that you'll need to know before we begin is that the
DbMigrator class, for reasons unclear, requires the Entity Framework
Configuration class but uses it in a way that's incompatible with the
Update-Database and
Add-Migration scripts, even after manually configuring the
ContextType and
ContextKey properties. We'll set those anyway for consistency, but no matter where you store your migrations and however diligently you inform the
DbMigrator (the
MigrationsDirectory property was ignored too) you're going to be stuck with automatic migrations. And while we're fiddling with the
Configuration class, be sure to make the
internal Configuration class
public.
Automatic migrations ignore the explicit migration files and detect changes between the context's models and the database. As with the
Update-Database script, the database will be created if it hasn't been already. It will not function reliably unless the
AutomaticMigrationDataLossAllowed property is set to true, and you'll also need to update the
OnModelCreating method of your context class to allow for database calls when the models are out of sync to give you a chance to run the migrations:
Migrating up and down
Using automatic migrations to update your database is great, but what do you do if you need to roll back?
DbMigrator requires a migration name to update to, and unlike the case with explicit migrations, the migration name is not established by the developer but is unique to the database in question.
Fortunately, the
DbMigrator includes the
GetDatabaseMigrations method, which returns a list of applied migrations; so while you won't be able to roll back to a predefined named state, you will be able to roll back to a previously run migration. Here it is important to note that the order of the migrations returned is not guaranteed, but the names begin with a timestamp so they're not too difficult to sort.
So rolling back the first of that list is as simple as
Seeding
Seeding must be performed manually after calling
DbMigrator.Update(). The
Configuration class'
Seed method is protected, so add the following wrapper method to your
Configuration class
and call it once the migration is complete.