Using Entity Framework (code first) migrations in production

.NetEntity FrameworkEf Code-FirstEntity Framework-Migrations

.Net Problem Overview


I'm just looking into using EF migrations for our project, and in particular for performing schema changes in production between releases.

I have seen mentioned that there is an API to perform these migrations at run-time using the DbMigration class, but I can't find any specific examples.

Ideally, I would want one DbMigration file for every database change, and for those changes to be applied automatically on application start up from the current version up to the latest version.

.Net Solutions


Solution 1 - .Net

There is a Database Initializer you can use to achieve the migration to latest version on startup (or better, the dbinitializer will kick in on first db access), the MigrateDatabaseToLatestVersion, you use it like that:

Database.SetInitializer<ObjectContext>(
    new MigrateDatabaseToLatestVersion<ObjectContext, Configuration>());

Regarding having one file per migration, if you enable automatic migrations you will find them in the Migrations folder (by default) in the root of your project.

Relevant info, with examples, here: http://weblogs.asp.net/fredriknormen/archive/2012/02/15/using-entity-framework-4-3-database-migration-for-any-project.aspx

Solution 2 - .Net

This works too:

var configuration = new MyDbContextConfiguration();
configuration.TargetDatabase = new DbConnectionInfo(
    database.ConnectionString, database.ProviderName);

var migrator = new DbMigrator(configuration);
migrator.Update();

You can also call:

migrator.GetPendingMigrations();

to get a list of the migrations it needs to apply.

Solution 3 - .Net

Since you didn't specify which Visual Studio version you are using, or Database, I will add an answer here to say that in VS2015 with Microsoft's SQL Server, this is now incredibly easy using the "Publish" tool.

You do not need to bother with the API you speak of. Simply do your work locally, changing your models, applying migrations etc, then when you want to push out to release/test servers, use the publish tool.

You can select to apply any migrations you have made locally, to the remote server the first time the application is started up.

Once you have all of your migrations and everything done locally (presumable in your Dev env) then you publish (right click the project, click "Publish..." Tick the "Execute Code First Migrations (runs on application startup)" checkbox under the "Settings" tab and then it will apply the migrations the first time the app is accessed (so there will be a short delay the first time).

Publish Web using Web-Deploy

Guide: https://msdn.microsoft.com/en-us/library/dd465337(v=vs.110).aspx

I learned all this because I had to do this to a Windows 2012 server: http://www.sherweb.com/blog/how-to-install-webdeploy-on-windows-server-2012/

Good luck!

Solution 4 - .Net

I wanted to control which migrations run explicitly in code and after a lot of search i managed to develop the following technique without the need of a DbConfiguration class or automatic migrations enabled:

public static void RunMigration(this DbContext context, DbMigration migration)
{            
    var prop = migration.GetType().GetProperty("Operations", BindingFlags.NonPublic | BindingFlags.Instance);
    if (prop != null)
    {
        IEnumerable<MigrationOperation> operations = prop.GetValue(migration) as IEnumerable<MigrationOperation>;
        var generator = new SqlServerMigrationSqlGenerator();
        var statements = generator.Generate(operations, "2008");
        foreach (MigrationStatement item in statements)
            context.Database.ExecuteSqlCommand(item.Sql);
    }
}

And if we had a migration like this:

public class CreateIndexOnContactCodeMigration : DbMigration
{
    public override void Up()
    {
        this.CreateIndex("Contacts", "Code");
    }

    public override void Down()
    {
        base.Down();
        this.DropIndex("Contacts", "Code");
    }
}

We would use it like that:

using (var dbCrm = new CrmDbContext(connectionString))
{
    var migration = new CreateIndexOnContactCodeMigration();
    migration.Up();                
    dbCrm.RunMigration(migration);
}

Regards.

Solution 5 - .Net

To add to all the answers already posted. Entity Framework uses a table: dbo.__MigrationHistory to keep track of all the migrations that have already been applied to the database to avoid running a migration that for example: inserts data or changes the database schema.

If you wish to run a script such as run adding data or changing the schema of the database you can create an empty migration using Package Manager Console and run the script via the the newly added migration. Ensure you use the initializer is used to prevent EF from dropping and recreating the database on every run.

     public override void Up()
    {
        string directoryToSearchScripts = Path.GetFullPath(Path.Combine(AppDomain.CurrentDomain.BaseDirectory, "..\\..\\"));

        string scriptFilePath = Directory.GetFiles(directoryToSearchScripts, "dummy-script.sql", SearchOption.AllDirectories).FirstOrDefault();
        if (!string.IsNullOrEmpty(scriptFilePath))
        {
            string fundsSqlScript = File.ReadAllText(scriptFilePath);
            Sql(fundsSqlScript);
        }
    }
    
    public override void Down()
    {
    }

When you publish the application and check the "Execute Code First Migrations" option, EF will run the migrations that have not yet been applied to the database.

Attributions

All content for this solution is sourced from the original question on Stackoverflow.

The content on this page is licensed under the Attribution-ShareAlike 4.0 International (CC BY-SA 4.0) license.

Content TypeOriginal AuthorOriginal Content on Stackoverflow
QuestiondevdigitalView Question on Stackoverflow
Solution 1 - .NetWDRustView Answer on Stackoverflow
Solution 2 - .NetmackieView Answer on Stackoverflow
Solution 3 - .NetWorthy7View Answer on Stackoverflow
Solution 4 - .NetPanos RoditakisView Answer on Stackoverflow
Solution 5 - .NetLuTheZyView Answer on Stackoverflow