【问题标题】:Entity Framework: Running code before all migrations实体框架:在所有迁移之前运行代码
【发布时间】:2014-10-18 02:34:13
【问题描述】:

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

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

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

有什么东西可以让我在所有迁移之前始终运行代码

【问题讨论】:

  • 现在猜猜为什么严肃的项目尽可能远离 EF 迁移。他们。做。不是。工作。 - 除了最简单的情况。等到您需要使用服务器端数据转换进行多阶段迁移 - 然后有趣的事情就开始了。不值得在 EF 中这样做。我总是使用一组外部 SQL 更改文件。
  • @TomTom 到目前为止,我只使用了一点点,但我看不出我可以用 FluentMigrator 做什么,但不能在这里做。外部 SQL 对我来说不是一个选择,因为即使是微不足道的正则表达式转换也会变成一个巨大的痛苦。尽管现在我想到了,他们可能使用了相同的延迟模型,该模型不允许正确混合代码和 SQL。我需要研究。

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


【解决方案1】:

我有一个非常糟糕的解决方案,但适用于 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
 }

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

【讨论】:

    【解决方案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。我不确定在早期版本的实体框架中是否有等价物。

    【讨论】:

    • 这是个好主意,但它似乎不适用于 migrate.exe (没有使用自定义初始化程序,实际上我不确定是否使用了初始化程序)。
    猜你喜欢
    • 2013-12-29
    • 2014-12-19
    • 2013-03-17
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多