【问题标题】:Entity Framework 6.1.3 initialize existing, but empty database from code-first modelEntity Framework 6.1.3 从代码优先模型初始化现有但为空的数据库
【发布时间】:2017-03-07 09:27:21
【问题描述】:

我在为生产系统上的发布准备应用程序时遇到了一些问题。

情况:

  • Entity Framework 6.1.3 Code-First Model 与多个迁移
  • 具有专用服务用户(非本地系统)的 Windows 服务
  • 配置(由 WPF 应用程序处理)允许粘贴指向所需 MS-SQL DB 的连接字符串
  • DB 应该由安装管理员准备,以便 serviceuser 拥有 dbowner、dbwriter 和 dbreader 权限。 (对于未来的迁移应该足够了)
  • serviceuser 不应拥有 SQL-Servers masterdb 的权限。这就是为什么在启动服务之前必须由管理员创建 Windows 服务所需的数据库的原因

我想要做什么:

  • 编写 IDatabaseInitializer,它会在检测到时初始化现有但为空的数据库,并在模型过时时更新数据库

我尝试了什么:

  • 使用 MigrateDatabaseToLatestVersion 初始化程序 => 这个失败,因为准备好的空数据库中没有 __MigrationHistory 表

  • 使用 CreateDatabaseIfNotExists 初始化程序 => 这个失败,因为数据库已经存在,这导致该初始化程序执行...什么都不做

  • 使用以下 InitializeDatabase 方法编写我自己的 IDbInitializer:

    public void InitializeDatabase(RapasiDbContext context)
    {
        if (!context.Database.Exists()) //Shouldn't happen
        {                
          ... // Throw Execption: No prepared DB found
        }           
        try //Initialize the existing database, but only if not already done (force:false)
        {
            context.Database.InitializeDatabase(false);
        }
        catch (Exception ex)
        {
            Log.Fatal("Error while initializing the database", ex);
        }           
        try //Update the databse, if model is outdated
        {
            var dbMigrationConfig = new Configuration();
            if (dbMigrationConfig.AutomaticMigrationsEnabled && !context.Database.CompatibleWithModel(true))
            {
                Log.Info("database schame outdated, starting migration!");
                try
                {
                    var migrator = new DbMigrator(dbMigrationConfig);
                    migrator.Update();
                }
                catch (Exception ex)
                {
                    Log.Fatal("Error while migrating the database", ex);
                }
            }
        }
        catch (Exception ex)
        {
            Log.Fatal("No Migration-Histroy found!", ex);
        }
    }
    

问题

  • 按照我现在尝试的方式,它根本没有调用初始化程序
  • 切换到 InitializeDatabase(force:true) 会导致递归调用我自己的 InitializeDatabase 方法:(

问题:

如何使用我的迁移中的 InitialCommit-Up() 脚本初始化现有数据库?

或者我错过了一些非常明显的观点,为什么这种数据库初始化不应该发生?对于我不知道的情况,是否有任何最佳做法?

【问题讨论】:

  • MigrateDatabaseToLatestVersion 初始化程序应该可以工作,即使没有 __MigrationHistory 表。它应该在第一次运行迁移时创建。问题应该出在其他任何地方。你有什么例外吗?
  • 另外,我认为您可能错误地解释了AutomaticMigrations 配置。这并不意味着您的迁移将自动应用,这意味着如果您在模型更改后没有手动运行Add-Migration,它们将自动生成。我猜您希望在数据库不是最新的情况下执行待处理的迁移,即使 AutomaticMigrations 已禁用。
  • 感谢您的建议,我在做一些更深入的测试后发现,MigrateDatabaseToLatestVersion 初始化程序有效,如果使用如下两个参数调用:Database.SetInitializer(new MigrateDatabaseToLatestVersion<RapasiDbContext, Configuration>(true, new Configuration()));。如果您编辑评论并将其发布在下面,将接受它作为答案:)
  • 感谢您解释基于AutomaticMigrations-Property 应用和生成迁移的区别!

标签: c# entity-framework entity-framework-6 code-first entity-framework-migrations


【解决方案1】:

MigrateDatabaseToLatestVersion 初始化程序应该可以工作,即使没有 __MigrationHistory 表。它应该在第一次运行迁移时创建。

正如您在原始问题的评论中所说,在调用 SetInitializer 方法时,您需要为 MigrateDatabaseToLatestVersion 的构造函数参数提供正确的值:

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

正如the reference page 所说,构造函数中的布尔参数指定是否使用触发初始化的上下文中的连接信息来执行迁移。如果缺少此参数,则将从使用默认构造函数或注册工厂构造的上下文中获取连接信息(这可能不是您需要的)。

另外,我认为您可能错误地解释了 AutomaticMigrations 配置。这并不意味着您的迁移将自动应用,这意味着如果您在模型更改后没有手动运行 Add-Migration,它们将自动生成。我猜您希望在数据库不是最新的情况下执行待处理的迁移,即使 AutomaticMigrations 被禁用。

【讨论】:

    猜你喜欢
    • 2013-09-23
    • 2013-07-10
    • 2011-07-04
    • 1970-01-01
    • 2016-02-29
    • 2011-08-21
    • 1970-01-01
    • 2013-03-13
    • 1970-01-01
    相关资源
    最近更新 更多