RMD*_*RMD 12 tfs release-management ef-code-first ef-migrations ms-release-management
我正在使用TFS版本管理来进行持续集成和部署.
我在部署期间使用migrate.exe来执行数据库迁移,当您从旧版本迁移到较新版本时,这非常有用.但是,当您想要部署旧版本的应用程序时,它会变得更加混乱.
基本上,保存上下文迁移的程序集必须知道如何从第3版转到第2版.通常,您使用要部署的程序集作为迁移的源,但在这种情况下,您必须使用已部署的程序集,因为他们是唯一知道如何从v3下载到v2的人.(版本2不知道v3甚至存在.)
我目前的计划是在部署期间以某种方式比较两个程序集.如果安装目录中的程序集包含"部署控制器"中的"更新"迁移,我首先需要在部署目录中的程序集中获取"最新"可用迁移,然后执行:
migrate.exe AssemblyInInstallationDir /targetMigration NewestFromAssemblyInDeploymentDir
Run Code Online (Sandbox Code Playgroud)
在您正在升级到较新版本的"正常"部署方案中,您可以这样做:
migrate.exe AssemblyInDeploymentDir
Run Code Online (Sandbox Code Playgroud)
这是一种合法的做法吗?我还没有考虑使用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();
}
Run Code Online (Sandbox Code Playgroud)
}
应用程序的输出如下所示:
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
Run Code Online (Sandbox Code Playgroud)
    我们实际上解决了这个问题,并且已经使用我们的工具一年多了,将完全连续的数据库部署到生产中。没有人类参与。:)
我们已在 GitHub 上公开了其中的一些内容: https: //github.com/GalenHealthcare/Galen.Ef.Deployer
您可以进行“重大”更改,但一般来说,我们也会避免这种情况 - 但主要是因为我们的应用程序在升级期间保持活动状态。我们将数据层视为可独立部署的组件 - 因此,它有一个需要保持兼容的“接口”。
我们经常使用多阶段升级方法,部署向后/向前兼容的中间版本,升级各种应用程序服务,然后最终升级数据库层以消除旧兼容性。
即使在这种情况下,我们也能够自动从/到任何版本的模式和数据。事实上,我们添加了单元测试,每次为每个数据库版本构建时都会验证这一点。它基本上沿着模式迭代链向上/向下走,并验证向上和向下迁移始终有效并保持数据一致性和兼容性。您可以在 GitHub 项目中看到这些测试。这是一个例子:
|   归档时间:  |  
           
  |  
        
|   查看次数:  |  
           1281 次  |  
        
|   最近记录:  |