Entity Framework 6.1.3 从代码优先模型初始化现有的空数据库
Entity Framework 6.1.3 initialize existing, but empty database from code-first model
我在准备在生产系统上发布的应用程序时遇到了一些问题。
情况:
- Entity Framework 6.1.3 具有多个迁移的代码优先模型
- 具有专用服务用户(非本地系统)的 windows 服务
- 配置(由 WPF-App 处理)允许粘贴指向所需 MS-SQL DB
的连接字符串
- 数据库应该由安装管理员准备,以便服务用户具有dbowner、dbwriter 和dbreader 权限。 (对于未来的迁移应该足够了)
- 服务用户不应该拥有 SQL-Servers masterdb 的权限。这就是为什么 windows 服务所需的数据库必须由管理员在启动服务之前创建
我正在尝试做的事情:
- 编写 IDatabaseInitializer
,它在检测到时初始化现有但空的数据库,并在模型过时时更新数据库
我试过的:
使用 MigrateDatabaseToLatestVersion 初始值设定项 => 这个失败了,因为准备好的数据库中没有 __MigrationHistory table,但是数据库是空的
使用 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);
}
}
问题
- 按照我现在尝试的方式,它根本没有调用 Initializer
- 切换到 InitializeDatabase(force:true) 导致递归调用我自己的 InitializeDatabase 方法:(
问题:
如何使用迁移中的 InitialCommit-Up() 脚本初始化现有数据库?
或者我错过了一些非常明显的点,为什么这种数据库初始化不应该发生?有什么我不知道的适合我的情况的最佳做法吗?
MigrateDatabaseToLatestVersion
初始化程序应该可以工作,即使没有 __MigrationHistory
table。它应该在第一次迁移 运行 时创建。
正如您在原始问题的评论中所说,调用 SetInitializer
方法时需要为 MigrateDatabaseToLatestVersion
的构造函数参数提供正确的值:
Database.SetInitializer(new MigrateDatabaseToLatestVersion<RapasiDbContext, Configuration>(true, new Configuration()));
正如the reference page所说,构造函数中的布尔参数指定是否使用触发初始化的上下文中的连接信息来执行迁移。如果缺少此参数,将从使用默认构造函数或注册工厂构造的上下文中获取连接信息(这可能不是您需要的)。
此外,我认为您可能错误地解释了 AutomaticMigrations 配置。这并不意味着您的迁移将自动应用,这意味着如果您在模型更改后没有手动 运行 添加迁移,它们将自动生成。我想您希望在您的数据库不是最新时执行您的挂起迁移,即使禁用了 AutomaticMigrations。
我在准备在生产系统上发布的应用程序时遇到了一些问题。
情况:
- Entity Framework 6.1.3 具有多个迁移的代码优先模型
- 具有专用服务用户(非本地系统)的 windows 服务
- 配置(由 WPF-App 处理)允许粘贴指向所需 MS-SQL DB 的连接字符串
- 数据库应该由安装管理员准备,以便服务用户具有dbowner、dbwriter 和dbreader 权限。 (对于未来的迁移应该足够了)
- 服务用户不应该拥有 SQL-Servers masterdb 的权限。这就是为什么 windows 服务所需的数据库必须由管理员在启动服务之前创建
我正在尝试做的事情:
- 编写 IDatabaseInitializer
,它在检测到时初始化现有但空的数据库,并在模型过时时更新数据库
我试过的:
使用 MigrateDatabaseToLatestVersion 初始值设定项 => 这个失败了,因为准备好的数据库中没有 __MigrationHistory table,但是数据库是空的
使用 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); } }
问题
- 按照我现在尝试的方式,它根本没有调用 Initializer
- 切换到 InitializeDatabase(force:true) 导致递归调用我自己的 InitializeDatabase 方法:(
问题:
如何使用迁移中的 InitialCommit-Up() 脚本初始化现有数据库?
或者我错过了一些非常明显的点,为什么这种数据库初始化不应该发生?有什么我不知道的适合我的情况的最佳做法吗?
MigrateDatabaseToLatestVersion
初始化程序应该可以工作,即使没有 __MigrationHistory
table。它应该在第一次迁移 运行 时创建。
正如您在原始问题的评论中所说,调用 SetInitializer
方法时需要为 MigrateDatabaseToLatestVersion
的构造函数参数提供正确的值:
Database.SetInitializer(new MigrateDatabaseToLatestVersion<RapasiDbContext, Configuration>(true, new Configuration()));
正如the reference page所说,构造函数中的布尔参数指定是否使用触发初始化的上下文中的连接信息来执行迁移。如果缺少此参数,将从使用默认构造函数或注册工厂构造的上下文中获取连接信息(这可能不是您需要的)。
此外,我认为您可能错误地解释了 AutomaticMigrations 配置。这并不意味着您的迁移将自动应用,这意味着如果您在模型更改后没有手动 运行 添加迁移,它们将自动生成。我想您希望在您的数据库不是最新时执行您的挂起迁移,即使禁用了 AutomaticMigrations。