如何在我的ssdt post部署脚本中有条件地包含大脚本?

时间:2016-05-10 16:01:22

标签: sql sql-server sql-server-2014 sql-server-data-tools

在我们的SSDT项目中,我们有一个庞大的脚本,包含许多用于从旧系统导入数据的INSERT语句。使用sqlcmd变量,我希望能够有条件地将文件包含在部署后脚本中。

我们目前正在使用包含内联脚本的:r语法:

IF '$(ImportData)' = 'true'
BEGIN
  :r .\Import\OldSystem.sql
END

这是一个问题,因为无论$(ImportData)是真还是假,脚本都包含在内嵌中,而且文件太大,以至于它的构建速度减慢了大约15分钟。

是否有另一种有条件地包含此脚本文件的方法,因此它不会减慢构建速度?

4 个答案:

答案 0 :(得分:2)

而不是将我之前的答案与另一个人混淆。有一个非常简单的特殊情况。

为每种执行可能性创建单独的SQLCMD输入文件。 这里的关键是使用控制变量的值命名执行输入文件。

因此,例如,您的发布脚本定义了变量'Config',它可能具有以下值之一:'Dev','QA'或'Prod'。

创建3个名为'DevPostDeploy.sql','QAPostDeploy.sql'和'ProdPostDeploy.sql'的部署后脚本。

对您的实际帖子部署文件进行编码,如下所示:

:r。“\”$(Config)PostDeploy.sql

这非常类似于构建事件机制,除非您不需要构建事件,否则使用适当的脚本覆盖脚本。但是你依赖于非常具体地命名你的脚本。

答案 1 :(得分:1)

始终包含使用:r引用的脚本。你有几个选择,但我首先会验证,如果你把脚本拿出来,它会将性能提高到你想要的地方。

最简单的方法是将其置于整个构建过程之外并更改部署过程,以使其变为两步(部署DAC然后部署脚本)。这样做的好处是你可以在ssdt进程之外做一些事情,但是否定的是你不会在部署中改变对表的约束的自动禁用。

第二种方法是在构建时不在部署中包含脚本,但创建AfterBuild msbuild任务,将脚本添加为dacpac中的post deploy脚本。 dacpac是一个zip文件,因此您可以使用.net包装Api添加一个名为postdeploy.sql的部件,然后将其包含在部署过程中。

这两种方式都意味着您将失去验证,因此您可能希望将其保存在一个单独的ssdt项目中,该项目具有相同的数据库"对你的主项目的引用,它会在构建发生变化时减慢构建速度,但在其余时间应该很快。

答案 2 :(得分:0)

这是我必须这样做的方式。

1)创建一个虚拟的部署后脚本。

2)在项目中为每个部署方案创建构建配置。

3)使用预构建事件来确定要使用的部署后配置。 您可以为每个配置创建单独的脚本,也可以在预构建事件中动态构建部署后脚本。无论哪种方式,您都可以根据构建事件中始终存在的$(配置)值进行操作。

如果使用单独的静态脚本,则构建事件只需复制相应的静态文件,使用在该部署方案中有用的任何脚本覆盖虚拟后部署。

在我的情况下,我不得不使用动态生成,因为决定要包含哪些脚本需要知道正在部署的数据库的当前状态。所以我使用配置变量告诉我正在部署哪个环境,然后使用SQLCMD脚本:OUT设置为我的Post-Deploy脚本位置。因此,我的预构建脚本将动态编写部署后脚本。

无论哪种方式,一旦构建完成并且正常部署过程启动,Post-Deploy脚本就包含我想要的:r命令。

这是我在预构建中调用的SQLCMD脚本的示例。

:OUT .\Script.DynamicPostDeployment.sql

PRINT ' /*';
PRINT '     DO NOT MANUALLY MODIFY THIS SCRIPT.                                               ';
PRINT '                                                                                       ';
PRINT '     It is overwritten during build.                                                   ';
PRINT '     Content IS based on the Configuration variable (Debug, Dev, Sit, UAT, Release...) ';
PRINT '                                                                                       ';
PRINT '     Modify Script.PostDeployment.sql to effect changes in executable content.         ';
PRINT ' */';
PRINT 'PRINT ''PostDeployment script starting at''+CAST(GETDATE() AS nvarchar)+'' with Configuration = $(Configuration)'';';
PRINT 'GO';
IF '$(Configuration)' IN ('Debug','Dev','Sit')
BEGIN
    IF (SELECT IsNeeded FROM rESxStage.StageRebuildNeeded)=1
    BEGIN
        -- These get a GO statement after every file because most are really HUGE
        PRINT 'PRINT ''ETL data was needed and started at''+CAST(GETDATE() AS nvarchar);';
        PRINT '                                                  ';
        PRINT 'EXEC iESxETL.DeleteAllSchemaData ''pExternalETL'';';
        PRINT 'GO';
        PRINT ':r .\PopulateExternalData.sql         ';
....

答案 3 :(得分:0)

我最终使用了我们的构建工具(Jenkins)和SSDT的混合来实现这一目标。这就是我所做的:

  1. 为每个写入文本文件的特定于环境的Jenkins作业添加了构建步骤。我要么写一个包含导入文件的SQLCMD命令,要么根据用户选择的构建参数将其留空。
  2. 通过:r在Post Deployment脚本中包含新文本文件。
  3. 那就是它!我也使用相同的方法根据应用程序版本选择要包含在项目中的部署前后脚本,除了我从代码中获取版本号并使用VS中的预构建事件将其写入文件在构建工具中。 (我还将文本文件名添加到.gitignore,因此它没有被提交)

相关问题