EF代码首次迁移到部署旧版本 [英] EF Code First Migrations to Deploy Older Version

查看:148
本文介绍了EF代码首次迁移到部署旧版本的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我正在使用TFS发行管理来进行持续的集成和部署。

I'm using TFS Release Management to do continuous integration and deployment.

我正在使用migrate.exe在部署过程中执行数据库迁移,当你从旧版本到较新版本时,这很棒。当您要部署较旧版本的应用程序时,它会变得更加笨拙。

I'm using migrate.exe to perform the database migration during deployment, and this works great when you're going from an older version to a newer version. When you want to deploy an older version of the application, however, it gets more muddy.

基本上,保存上下文迁移的程序集必须知道如何执行从版本3到版本2.通常,您将使用要部署的程序集作为迁移源,但在这种情况下,您必须使用已部署的程序集,因为它们是唯一知道如何从v3到v2。 (版本2不知道v3是否存在。)

Basically, the assembly that holds your migrations for a context must know how to go from say version 3 to version 2. Normally, you use the assemblies you're about to deploy as the source of your migrations, but in this case, you must use the already deployed assemblies as they're the only ones who know how to get from v3 down to v2. (Version 2 has no idea that v3 even exists.)

我目前的计划是以某种方式比较部署期间的两个程序集。如果安装目录中的程序集包含部署指导器中的更新迁移,我首先需要在部署目录中的程序集中获取最新的可用迁移,然后执行:

My current plan is to somehow compare the two assemblies during deployment. If the assembly in the installation directory contains "newer" migrations than the one in the deployment director, I would first need to get the "newest" available migration in the assembly in the deployment directory, and then execute:

migrate.exe AssemblyInInstallationDir /targetMigration NewestFromAssemblyInDeploymentDir

如果在升级到较新版本的正常部署场景中,您可以执行以下操作:

Where as in a "normal" deployment scenario where you are upgrading to a newer version, you can just do:

migrate.exe AssemblyInDeploymentDir

这是一个合法的方法吗?我还没有研究使用EF库来评估每个程序集中可用的迁移。同样的挑战在于,这些组件中的每一个都是相同的仅仅是不同的版本。我可能需要将它们加载到单独的应用程序域中,然后使用跨应用程序域名通信获取我需要的信息。

Is this a legit approach? I have yet to look into using EF libraries to evaluate what migrations are available in each assembly. There is also the challenge of the fact that each of these assemblies are the "same" just different versions. I'll probably have to load them into separate app domains and then use cross-app domain communications to get the information I need.

编辑

我创建了一个概念验证应用程序,允许我列出可用迁移到同一程序集的两个不同版本。这对整个过程至关重要,所以我认为这是值得记录的。

I created a proof of concept app that allows me to list the available migrations to two different versions of the same assembly. This was critical to this entire process, so I figured it's worth documenting.

应用程序使用反射来加载每个程序集,然后使用System.Data中的DbMigrator类.Entity.Migrations来枚举迁移元数据。迁移的名称以时间戳信息为前缀,从而允许我订购它们,并查看哪个程序集包含较新的迁移集。

The app uses reflection to load each of the assemblies and then uses the DbMigrator class from System.Data.Entity.Migrations to enumerate the migration meta data. The names of the migrations are prefixed with the timestamp information, thereby allowing me to order them and see which assembly contains the "newer" set of migrations.

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();
}

}

应用程序的输出如下所示:

The output of the application looks like:

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


推荐答案

我们实际上解决了这个问题,一直在使用我们的工具一年多,数据库部署int o生产。没有人参与:)

We actually solved this problem and have been using our tooling for over a year now to do fully continuous database deployments into production. No humans involved. :)

我们已经在GitHub上进行了一些公开: https://github.com/GalenHealthcare/Galen.Ef.Deployer

We've made some of this public on GitHub: https://github.com/GalenHealthcare/Galen.Ef.Deployer

您可以进行打破更改,但一般来说,我们也避免了这一点,但主要是因为我们的应用程序在升级过程中保持现状。我们将数据层视为可独立部署的组件,因此它具有需要保持兼容性的接口。

You can make "breaking" changes, but generally, we avoid that as well - but mostly because our applications remain live during upgrades. We treat the data tier as an independently deployable component - and as a result, it has an "interface" that needs to remain compatible.

我们经常会采用多阶段升级方式,我们部署了向后兼容的中间版本,升级各种应用服务,然后最终升级数据库层删除旧的兼容性。

We will often use a multi-phased upgrade approach where we deploy an intermediate version that's backwards/forwards compatible, upgrade our various application services, and then finally upgrade the database tier to remove the legacy compatibility.

即使在这种情况下,我们也有能力自动从/到任何版本的模式和数据。事实上,我们已经添加了单个测试,每次我们为每个数据库版本构建一次验证。它基本上向上/向下移动模式迭代链,并验证向上和向下迁移始终工作并维护数据的一致性和兼容性。您可以在GitHub项目中看到这些测试。以下是一个例子:

Even in that scenario, we have the ability to automatically go from/to any version of our schema and data. In fact, we've added unit tests that verify this every single time we build for every single database version. It basically walks up/down the chain of schema iterations and validates that the upward and downward migrations always work and maintain data consistency and compatibility. You can see these tests in the GitHub project. Here is an example:

https://github.com/GalenHealthcare/Galen.Ef.Deployer/blob/master/Galen.Ci.EntityFramework.Deployer/Galen .Ci.EntityFramework.Testing / MigrationTestRunner.cs

这篇关于EF代码首次迁移到部署旧版本的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆