Andrey Shchekin
Andrey Shchekin

Reputation: 21629

Entity Framework: Running code before all migrations

I want to migrate stored procedures and views in my DB. Since I always migrate to the latest version, a source-control-friendly approach is to drop/recreate all procedures/views during migration process (with this approach there is one file per procedure, instead of one-per-version).

Since old procedures/functions/views might not be compatible with new schema changes, I want to do drop before all migrations, then do the create after all.

Previously I used a customized FluentMigrator, but now I am researching Entity Framework Code First Migrations. I see that I can use Seed to always run code after all migrations.

Is there something I can use to always run code before all migrations?

Upvotes: 5

Views: 2759

Answers (2)

Andrey Shchekin
Andrey Shchekin

Reputation: 21629

I have a solution that is pretty horrible, but works for migrate.exe.

Here is the idea:

  1. Use Seed for AfterAll, as suggested by @khellang.
  2. For BeforeAll, register a custom IDbConnectionInterceptor in MigrationsConfiguration constuctor to capture first connection after the MigrationsConfiguration has been created, then make it unregister itself. Obviously this is absolutely not thread-safe and only OK in application startup or migrate.exe.

Example code:

public class DbMigrationsInterceptingConfiguration<TContext> : DbMigrationsConfiguration<TContext> 
    where TContext : DbContext
{
    public DbMigrationsInterceptingConfiguration() {
        BeforeFirstConnectionInterceptor.InterceptNext();
    }

    protected override void Seed(TContext context) {
        Console.WriteLine("After All!");
    }
}

internal class BeforeFirstConnectionInterceptor : IDbConnectionInterceptor {
    public static void InterceptNext() {
        DbInterception.Add(new BeforeFirstConnectionInterceptor());
    }

    public void Opened(DbConnection connection, DbConnectionInterceptionContext interceptionContext) {
        // NOT thread safe

        Console.WriteLine("Before All!");
        DbInterception.Remove(this);
    }

    // ... empty implementation of other methods in IDbConnectionInterceptor
 }

I am not sure I would be actually using it though.

Upvotes: 2

khellang
khellang

Reputation: 18132

If you want some code to run before migrations kick in, you can specify a custom database initializer:

public class AwesomeEntity
{
    public int Id { get; set; }
}

public class AwesomeDbContext : DbContext
{
    static AwesomeDbContext()
    {
        Database.SetInitializer(new AwesomeDatabaseInitializer());
    }

    public IDbSet<AwesomeEntity> Entities { get; set; }
}

public class AwesomeDatabaseInitializer : MigrateDatabaseToLatestVersion<AwesomeDbContext, AwesomeMigrationsConfiguration>
{
    public override void InitializeDatabase(AwesomeDbContext context)
    {
        // TODO: Run code before migration here...

        base.InitializeDatabase(context);
    }
}

public class AwesomeMigrationsConfiguration : DbMigrationsConfiguration<AwesomeDbContext>
{
    public AwesomeMigrationsConfiguration()
    {
        AutomaticMigrationsEnabled = true;
    }

    protected override void Seed(AwesomeDbContext context)
    {
        // TODO: Seed database here...
    }
}

This sets the custom initializer to a custom AwesomeDatabaseInitializer, which inherits from MigrateDatabaseToLatestVersion. If you want to drop and rebuild the database every time, you should use the DropCreateDatabaseAlways as base class instead, though I'm not sure this lets you run migrations.

In the initializer, you can override the InitializeDatabase method, where you can run code before you call base.InitializeDatabase, which will trigger the database initialization and in turn the Seed method of the migration configuration, AwesomeMigrationsConfiguration.

This is using EF6. I'm not sure if there is an equivalent in earlier versions of entity framework.

Upvotes: 2

Related Questions