我正在使用 TFS 发布管理进行持续集成和部署。
我在部署期间使用 migrate.exe 执行数据库迁移,当您从旧版本升级到新版本时,这非常有用。但是,当您想要部署旧版本的应用程序时,它会变得更加混乱。
基本上,为上下文保存迁移的程序集必须知道如何从版本 3 转到版本 2。通常,您使用要部署的程序集作为迁移的源,但在这种情况下,您必须使用已经部署的程序集,因为它们是唯一知道如何从 v3 到 v2 的程序集。(版本 2 甚至不知道 v3 存在。)
我目前的计划是在部署期间以某种方式比较这两个程序集。如果安装目录中的程序集包含比部署目录中的“更新”迁移,我首先需要在部署目录中的程序集中获取“最新”可用迁移,然后执行:
migrate.exe AssemblyInInstallationDir /targetMigration NewestFromAssemblyInDeploymentDir
在升级到较新版本的“正常”部署场景中,您可以这样做:
migrate.exe AssemblyInDeploymentDir
这是一种合法的方法吗?我还没有考虑使用 EF 库来评估每个程序集中可用的迁移。还有一个挑战是这些程序集中的每一个都是“相同的”只是不同的版本。我可能必须将它们加载到单独的应用程序域中,然后使用跨应用程序域通信来获取我需要的信息。
编辑
我创建了一个概念验证应用程序,它允许我列出对同一程序集的两个不同版本的可用迁移。这对整个过程至关重要,所以我认为值得记录。
该应用程序使用反射来加载每个程序集,然后使用 System.Data.Entity.Migrations 中的 DbMigrator 类来枚举迁移元数据。迁移的名称以时间戳信息为前缀,因此我可以对它们进行排序并查看哪个程序集包含“较新”的迁移集。
static void Main(string[] args)
{
const string dllName = "Test.Data.dll";
var assemblyCurrent = Assembly.LoadFile(Path.Combine(System.Environment.CurrentDirectory, string.Format("Current\\{0}", dllName)));
var assemblyTarget = Assembly.LoadFile(Path.Combine(System.Environment.CurrentDirectory, string.Format("Target\\{0}", dllName)));
Console.WriteLine("Curent Version: " + assemblyCurrent.FullName);
Console.WriteLine("Target Version: " + assemblyTarget.FullName);
const string contextName = "Test.Data.TestContext";
const string migrationsNamespace = "Test.Data.Migrations";
var currentContext = assemblyCurrent.CreateInstance(contextName);
var targetContext = assemblyTarget.CreateInstance(contextName);
var currentContextConfig = new DbMigrationsConfiguration
{
MigrationsAssembly = assemblyCurrent,
ContextType = currentContext.GetType(),
MigrationsNamespace = migrationsNamespace
};
var targetContextConfig = new DbMigrationsConfiguration
{
MigrationsAssembly = assemblyTarget,
ContextType = targetContext.GetType(),
MigrationsNamespace = migrationsNamespace
};
var migrator = new DbMigrator(currentContextConfig);
var localMigrations = migrator.GetLocalMigrations(); //all migrations
Console.WriteLine("Current Context Migrations:");
foreach (var m in localMigrations)
{
Console.WriteLine("\t{0}", m);
}
migrator = new DbMigrator(targetContextConfig);
localMigrations = migrator.GetLocalMigrations(); //all migrations
Console.WriteLine("Target Context Migrations:");
foreach (var m in localMigrations)
{
Console.WriteLine("\t{0}", m);
}
Console.ReadKey();
}
}
应用程序的输出如下所示:
Curent Version: Test.Data, Version=1.3.0.0, Culture=neutral, PublicKeyToken=null
Target Version: Test.Data, Version=1.2.0.0, Culture=neutral, PublicKeyToken=null
Current Context Migrations:
201403171700348_InitalCreate
201403171701519_AddedAddresInfoToCustomer
201403171718277_RemovedStateEntity
201403171754275_MoveAddressInformationIntoContactInfo
201403181559219_NotSureWhatIChanged
201403181731525_AddedRowVersionToDomainObjectBase
Target Context Migrations:
201403171700348_InitalCreate
201403171701519_AddedAddresInfoToCustomer
201403171718277_RemovedStateEntity