我正在使用TFS Release Management进行持续集成和部署。
在部署过程中,我使用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