Evg*_*rov 5 database migration installation wix code-first
我正在使用 Wix 开发安装项目,并且正在使用迁移 .dll 文件安装数据库。
我计划使用 Migrate.exe 从 .dll 执行迁移,但有一个要求,如果运行较新版本的安装程序(使用较新的迁移),我必须更新数据库。我找不到使用 Migrate.exe 列出所有迁移并仅运行那些尚未针对已安装数据库运行的迁移的方法。
您是否知道使用 Migrate.exe 或任何其他工具或框架来满足此要求的方法,这将允许我跟踪迁移并仅运行那些未为数据库执行的迁移?
我应该能够在安装程序项目中实现建议的功能以使其正常工作。
谢谢。
最好的问候, Evgeni Dyulgerov
您不需要在安装过程中运行迁移脚本 - 您的安装程序需要太高的权限才能执行此操作,并且系统管理员从 Active Directory 应用的安装包策略可能会出现问题。
数据库升级也是应用程序逻辑,我相信它属于应用程序 - 而不是安装程序。
当然,您可以在wix 中使用自定义操作来完成此操作。但是您必须加载进行迁移所需的所有程序集 - 至少运行 SQL 命令。
我建议您在应用程序启动时运行迁移。
这是一个可以完成这项工作的剪辑。首先让我们了解一些上下文:
您可以使用 Visual Studio 中的包管理器控制台中的 EF 工具或直接使用 EF 工具(可以在 nuget 包中找到的 .exe)来创建部分(更新)迁移。之后您将在迁移程序集中编译它们,以便它们通过安装程序随您的应用程序一起传送到客户端。一个例子 :
Add-Migration -Name SomeDbChangeDescription -StartUpProjectName TheCoreProjectWithConfig -ProjectName TheProjectWithMigrations -ConfigurationTypeName "Fully.Qualified.Type.Name.Of.MigrationConfiguration" -ConnectionString "数据源=.\SQLINSTANCE;数据库=my-db;Trusted_Connection=False;用户 ID= xxx;密码=xxx" -ConnectionProviderName "System.Data.SqlClient"
请记住,使用此脚本,您可以从一个数据库生成迁移脚本,但稍后可以将其应用到多个数据库 - 当您有 db-per-tenant 时。如果每个数据库源自同一模型,则无需为每个数据库生成迁移脚本,因为在生成过程中迁移脚本中没有硬编码数据库特定信息。
现在您可以使用(根据需要修改)以下代码。dbMigrator.Update() 将应用需要应用的所有迁移脚本 - 如果程序集中有 10 个迁移,其中有 2 个未应用的迁移,它将比较数据库的模型和所有迁移,并且仅应用最后 2 个。如果您使用不存在的数据库名称调用 dbMigrator.Update() 方法,它将创建应用初始脚本和所有其他部分更新的新数据库。
public class DbInitializer : IDbInitializer
{
private readonly IConnectionStringProvider _connectionStringProvider;
public DbInitializer(IConnectionStringProvider connectionStringProvider)
{
_connectionStringProvider = connectionStringProvider;
}
public void CreateOrUpdateDb(string dbName)
{
try
{
string connectionString = _connectionStringProvider.GetConnectionString(dbName);
DbMigrationsConfiguration cfg = CreateMigrationsConfig(connectionString);
cfg.CommandTimeout = 900;
cfg.AutomaticMigrationsEnabled = false;
cfg.AutomaticMigrationDataLossAllowed = false;
DbMigrator dbMigrator = new DbMigrator(cfg);
var pendingMigrations = dbMigrator.GetPendingMigrations().ToArray();
if(pendingMigrations.Length > 0)
{
foreach(var pendingMigration in pendingMigrations)
{
InitializerEventSource.Log.UpgradingDb(dbName, pendingMigration);
}
dbMigrator.Update();
DbInitializerEventSource.Log.UpgradedDb(dbName);
}
}
catch(MigrationsException exception)
{
// exception handling
}
catch(Exception exception)
{
// exception handling
}
}
private DbMigrationsConfiguration<InitDbContext> CreateMigrationsConfig(string connectionString)
{
DbMigrationsConfiguration<InitDbContext> cfg = new DbMigrationsConfiguration<InitDbContext>
{
AutomaticMigrationsEnabled = false,
AutomaticMigrationDataLossAllowed = false,
MigrationsAssembly = Assembly.Load("TheAssemblyContainingTheMigrations"),
MigrationsNamespace = "TheNamespaceWhereTheMigrationsAre",
ContextKey = "HardCodedContexKey",
TargetDatabase = new DbConnectionInfo(connectionString, _connectionStringProvider.ProviderInvariantName)
};
return cfg;
}
}
Run Code Online (Sandbox Code Playgroud)
更新 您可以应用另一种方法 -