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

本文关键字:运行 代码 迁移 框架 实体 | 更新日期: 2023-09-27 18:19:14

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

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

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

在所有迁移之前,我是否可以使用某些东西来始终运行代码 ?

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

如果希望在迁移开始之前运行一些代码,可以指定一个自定义数据库初始化器:

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之前运行代码,这将触发数据库初始化,进而触发迁移配置AwesomeMigrationsConfigurationSeed方法。

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

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

思路如下:

  1. 按照@khellang的建议,使用Seed for AfterAll。
  2. 对于BeforeAll,在MigrationsConfiguration构造器中注册一个自定义IDbConnectionInterceptor,以便在MigrationsConfiguration创建后捕获第一个连接,然后使其取消注册。显然,绝对是不是线程安全的,只有在应用程序启动或migrate.exe时才可以。

示例代码:

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
 }

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