带有功能分支的.NET Rails风格的数据库迁移



我查看了.NET迁移引擎上的所有选项,发现使用Rails风格迁移的引擎是最有趣的,主要是因为它们是以与数据库无关的方式编写的,可以很容易地在不同的数据库平台上使用。

然而,我看到了一个明显的问题,它们似乎都无法开箱即用地解决:源代码管理分支。

场景

  1. 功能1正在branch1上开发,并将一列添加到名为column1的表中
  2. 功能2正在branch2上开发,并将一列添加到名为column2的同一表中
  3. 1.1版包含了功能2,但功能1尚未完成
  4. 功能1已完成并合并到主干
  5. 版本1.2已经发布,但是进入主干的新column1字段是版本1(在代码中直接与版本1.1绑定),因此在迁移时不会在数据库中更新

对于像Migrator.NET这样的工具,问题似乎是迁移版本与实际软件版本有关,而不是SCC提交。但是,必须在源代码管理中将属性添加到代码中。我看到过使用日期而不是版本的例子,但这似乎比增量版本控制更不能解决手头的问题。

我在Liquibase常见问题页面上找到了最接近答案的答案,但在.NET中的Rails风格框架的情况下(甚至在Rik Migrations中,它的属性结构类似于Liquibase更改日志文件),该解决方案需要更改代码:

Liquibase是否与分支机构合作是的。由于每个更改都是独立的,因此在不同的分支,然后在中合并将在下次运行Liquibase时运行。你语句的运行顺序可能会遇到问题,但是您遇到的任何问题都可以通过重新订购变更日志轻松解决文件。

处理这个问题的典型方法是什么?

如果有什么不同的话,我使用Git进行源代码管理。注意,我已经看到了题为"复杂分支系统中的数据库迁移"的文章,但它并没有真正提供答案。

我已经对此进行了一些思考,这就是我迄今为止所想到的。我还没有决定迁移框架,但下面的方法假设了类似于Migrator.NET的使用属性的方法。然而,这也可以适应其他迁徙者。

由于问题在于迁移版本过早(在开发过程中而不是在发布过程中),我的第一反应是制定一个工作流程,确保在发布之前不能对迁移进行版本控制。这可以通过构建脚本、单元测试和源代码管理来实现。以下是步骤:

  1. 当存在版本高于CI过程中运行的当前数据库版本的MigrationAttributes时,创建一个失败的单元测试
  2. 创建一个单元测试,当对等于或低于CI过程中运行的当前数据库版本的任何迁移进行更改时,该单元测试将失败
  3. 在CI生成之前添加一个步骤,查找从迁移类继承的所有类,并添加版本1高于当前数据库版本的MigrationAttribute。这样可以确保迁移在CI过程中成功运行。确保在本步骤之前运行步骤1和2中的单元测试
  4. 在CI生成后添加一个步骤,将数据库表中的当前数据库版本设置回当前发布的数据库版本。我们的CI流程数据库版本控制只是暂时的
  5. 在发布版本之前添加一个步骤,定位从Migration类继承的所有类,并添加版本1高于当前数据库版本的MigrationAttribute。将此代码更改提交回主干中

这里的共同前提是,所有这些都可以完全自动化,并且数据库迁移版本属性是作为临时CI构建步骤和发布步骤添加的(通过构建过程而不是手动添加)。单元测试确保在开发周期的早期编辑迁移或对其进行版本控制时不会作弊。

当然,在CI过程中,步骤3和4可以用丢弃/重新创建方法代替,而且可能更可靠。关键是数据库版本控制在发布过程中发生并被检查到源代码管理中(以前从未如此)。

版本控制

为了适应此工作流程,我正在考虑将数据库版本作为AssemblyInformation version属性的一部分

[assembly: AssemblyVersion("1.2.0.0")]
[assembly: AssemblyFileVersion("1.2.3.4")]
[assembly: AssemblyInformationalVersion("1.2.3.4+<GitHash>-<DBVersion>")]

因此,在上面的示例中,数据库的版本将插入Assembly之后。这将允许我使用常规的主/次+构建版本,但也可以跟踪程序集中当前构建的数据库发布版本(以及Git中的头提交)。发布过程可以相应地增加这个版本,所有的单元测试和其他步骤都会随之而来。请注意,AssemblyInvormationalVersion在Windows中显示为产品版本。

GitHash只有前7个字符,这通常足以使它具有唯一性。

摘要

需要注意的主要一点是,在不与数据库版本集成的情况下,分支可以像需要的那样复杂,因为源代码在任何分支中都不包含数据库版本控制属性(如果包含,则构建将失败)。但是,分支将包含迁移数据库所需的信息,这实际上是一个开发步骤,而不是发布步骤。

显然,单元测试和构建脚本将需要反射、代码注入,以及与源代码管理提供者合作以确保规则得到遵守,但这一切都是可能的。

我还没有在实践中测试过这一点,但如果我找不到另一个解决方案,这可能是我要走的方向。

最新更新