4

我正在使用 TeamCity 为我们的测试环境创建 .NET 应用程序(使用 SVN 源代码控制)的 CI 和自动部署,一切进展顺利。我正处于想要自动执行 db 脚本的阶段。我进行了一些搜索并阅读了几篇文章,例如http://www.troyhunt.com/2011/02/automated-database-releases-with.html(troyhunt的博客非常宝贵!),许多人似乎都指出使用 RedGate 软件管理和部署更改。我有点担心让新工具处理脚本生成,所以我想知道是否还有其他公认的方法值得研究。

我们当前的解决方案设计标准包括一个包含数据库相关文件的项目,例如我们的 orm db。它还包含一系列文件夹,其中包含我们的更改脚本,如下图所示。

MySolution
 > MySolution.Data
    > 3.0 Scripts
       * 01 - UpdateUserTable.sql
       * 02 - UpdateRoleTable.sql
    > 3.1 Scripts
       * 01 - CreateJobTable.sql
       * 02 - InsertJobTypes.sql
       * 03 - AndSoOn.sql

我相信这种结构很重要,因为虽然我们希望在签入时自动部署到我们的测试环境,但我们部署实际版本的频率要低得多,而且我不确定 RedGate 的比较工具是否可以处理有时发生的更改级别。这就是为什么我更愿意为脚本使用版本文件夹,然后在发布时增加次要版本以保持脚本版本整齐地包含。

有了这个预先存在的结构,我倾向于保留它并添加一个 TeamCity 构建定义,它可以在成功部署时应用 db 脚本。我想我可以让 TeamCity 在预期的路径中识别新添加的 .sql 文件到 SVN,然后在服务器上执行这些文件,但也许我期待太多了。我过去使用 TFS 和 MSBUILD 以及自定义构建步骤实现了这种解决方案,但对 TeamCity 方式来说是全新的。

是否已经有实现类似目标的过程?在我看来,这似乎是一个很正常的实现,我只是还没有弄清楚是怎么回事。还是 RedGate 解决方案是我们应该追求的标准?

4

3 回答 3

4

两年前我读过同样的特洛伊亨特文章。这是一个启示,我很快让我们使用 SQL Source Control + SQL Compare + TC 启动并运行。这是一个很好的解决方案,但是有些事情并没有像我想要的那样工作。其中最主要的是 SQL 源代码控制不能(或不能)很好地处理分支/合并策略。此外,SQL 源代码控制是一个带外过程,需要开发人员培训、采用和了解其怪癖。它从未扎根。我们的团队最终放弃了 RedGate,转而采用 TeamCity 驱动的实体框架迁移,而且我们没有回头。

对于您的直接问题:我认为您在这里尝试做的事情是可能的,尽管我认为寻找新添加的 SQL 脚本不一定是 TeamCity 的工作。Red Gate 和 Entity Framework 都识别数据库本身中最近部署的脚本/迁移,并在确定应该从哪里开始应用更改时引用它。您可以在数据库中存储类似的值('3.0'),或作为 TC 构建参数,然后使用 powershell 遍历较新的文件夹并使用sqlcmd应用最新的脚本。

不过,您可能会考虑查看基于 EF 的迁移,尤其是在您采用代码优先模型的情况下。如果您有兴趣,我可以更新此答案以更多地讨论我们如何做到这一点。

更新:

EF 代码优先迁移通过在迁移类中捕获一组离散的数据库架构更改来工作。这个类有一个Up和一个Down方法,可以应用/反转该特定批次的模式更改。这或多或少等同于 Ruby 和其他人的做法。

当您对实体模型进行更改(添加表、删除列、更改约束等)时,您可以通过Add-Migration <DescriptionOfSchemaChange>在包管理器控制台中调用来创建一个新的迁移类。这将生成名为<timestamp>_<DescriptionOfSchemaChange>.cs. 然后,您可以通过调用在本地应用该迁移Update-Database。实体框架为您管理细节,但您可以根据需要将任意 SQL 注入迁移步骤。PluralSight 提供了涵盖这些概念的精彩课程。

迁移由migrate.exe作为实体框架 NuGet 包的一部分部署的可执行文件 管理。在 TeamCity 中,您可以使用migrate.exe针对指定数据库运行迁移。首先,您必须将migrate.exe本地复制到包含迁移类的程序集。然后,您只需migrate.exe使用 DB 连接字符串作为参数对该程序集运行。工作目录是迁移程序集的目录。

copy ..\..\packages\EntityFramework.5.0.0\tools\migrate.exe .

migrate.exe ASSEMBLY.dll /connectionString="CONNECTION_STRING" /connectionProviderName="System.Data.SqlClient"

于 2013-09-03T13:53:49.573 回答
3

经过大量搜索和了解如何实现我的目标后,我决定继续编写自己的控制台应用程序来为我做这件事。我将在这里列出基本步骤,稍后可能会更详细地充实它们。

DatabaseRevisionUpdater(控制台应用程序)

  1. 使用 SVNSharp,DatabaseRevisionUpdater 连接到我们的 SVN 服务器,并将 SQL 脚本文件从指定的 SVN 修订范围读取到内存中。
  2. 在 .NET 创建的 Transaction 中,应用程序会一一读取脚本文件。如果在运行这些脚本时遇到任何错误,事务将回滚并且应用程序以错误代码 -1 退出。
  3. 目标数据库应包含一些新的日志记录表,这些表会在进行更新时写入。版本表跟踪进行了哪些修订,成功和失败。一个单独的表包含有关为此修订请求运行的每个脚本的信息(状态为成功、失败和已跳过)。
  4. 当进行未来更新时,数据库的版本由步骤 3 中的表确定。如果请求与任何先前成功的更新相交,则更新将不会继续,因为它假定它已被应用。SVN Update Revision From 也可以从这些表中确定。

TeamCity 集成

  • 添加了 Runner 类型的 Build Step:命令行
  • 工作目录是构建服务器上包含我的控制台应用程序的目录
  • 运行:自定义脚本(不要使用带参数的可执行文件,因为它似乎无法处理包含双引号的参数,例如我的 dbConnectionString)
  • 自定义脚本:可执行文件后跟针对我的数据库的参数。参数包括 svnUsername、svnPassword、svnPath、databaseConnectionString,最重要的是 RevisionTo。我使用 %build.vcs.number.APP_ID% 来获取当前版本的修订号。

额外使用 - 更新断开连接的数据库

这一切都适用于我们的测试环境,但我们的实时环境位于无法访问 svn 或互联网的隔离网络上(出于安全原因)。在我的控制台应用程序中,我使用了几种不同的模式。上面描述的模式是直接更新,这是一个多合一的解决方案。它通过查看其日志表来确定数据库的当前版本,它轮询 SVN 以获取所有更新,直到您指定的修订版,它针对目标数据库运行它们并相应地更新其日志表。对于我们的现场环境,我添加了几个额外的模式。出口和进口。

  • 导出用于从修订范围内的 SVN 获取脚本。然后将它们保存到 XML 文件中。它根本不关心目标数据库。
  • 导入用于导入 XML 数据文件并将其中的更新应用到目标数据库。它关心版本兼容性,但与SVN无关。

这基本上是我的解决方案。没有什么是开箱即用的,但它就像一个魅力。我可以让 TeamCity 与它很好地交互,并使用控制台输出详细描述该过程,使其尽可能透明。TeamCity 在其构建日志中报告所有这些输出,并且根据我的返回码为 0 或其他内容而失败或成功。

作为一个为期一周的旅程,我决定写一篇小博文,详细说明我是如何到达这里的,以防其他人感兴趣:https ://andrekriegler.wordpress.com/2013/09/12/auto-deploy-database/

于 2013-09-11T09:15:08.847 回答
0

在 Red Gate,我们目前正在研究我们所说的“迁移 v2”。这是一种数据库部署技术,既使用模式比较方法,也允许用户指定自己的脚本,例如在数据移动情况下。

一系列网页可以更好地描述这一点,还有一个 GoogleGroup 论坛

如果您对此功能有任何疑问,请告诉我。

于 2013-09-19T07:52:26.100 回答