实体框架:在所有迁移之前运行代码

时间:2014-08-25 00:13:24

标签: c# .net entity-framework database-migration ef-migrations

我想在我的数据库中迁移存储过程和视图。由于我总是迁移到最新版本,因此源代码控制友好的方法是在迁移过程中删除/重新创建所有过程/视图(使用此方法,每个过程只有一个文件,而不是每个版本一个)。 p>

由于旧的过程/函数/视图可能与新的模式更改不兼容,我想在所有迁移之前删除,然后再进行创建。

之前我使用过定制的FluentMigrator,但现在我正在研究实体框架代码优先迁移。我发现我可以使用Seed在所有迁移后始终运行代码。

在所有迁移之前,我可以使用什么来始终运行代码吗?

2 个答案:

答案 0 :(得分:2)

如果您希望在迁移开始之前运行某些代码,则可以指定自定义数据库初始化程序:

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...
    }
}

这会将自定义初始值设定项设置为自定义AwesomeDatabaseInitializer,继承自MigrateDatabaseToLatestVersion。如果您希望每次都删除并重建数据库,则应使用DropCreateDatabaseAlways作为基类,但我不确定这可以让您运行迁移。

在初始化程序中,您可以覆盖InitializeDatabase方法,在此方法中,您可以在调用base.InitializeDatabase之前运行代码,这将触发数据库初始化,并依次触发Seed方法。迁移配置,AwesomeMigrationsConfiguration

这是使用EF6。我不确定早期版本的实体框架中是否存在等价物。

答案 1 :(得分:2)

我有一个非常糟糕的解决方案,但适用于migrate.exe。

这是一个想法:

  1. 使用Seed for AfterAll,如@khellang所示。
  2. 对于BeforeAll,在MigrationsConfiguration构造函数中注册自定义IDbConnectionInterceptor以在创建MigrationsConfiguration后捕获第一个连接,然后使其取消注册。显然,绝对不是线程安全的,只有在应用程序启动或者migrate.exe中才能正常运行。
  3. 示例代码:

    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
     }
    

    我不确定我是否真的会使用它。