如何将转换应用于 SSDT 发布配置文件

How to Apply Transforms to SSDT publish profiles

使用 Visual Studio 2013

我有一组 8 个 SSDT 项目,它们都可以部署到几个不同的环境中。但是,每个项目的高级发布设置应该是相同的。目前我已经为每个环境创建了一个不同的发布配置文件,这意味着我有大约 20 个发布配置文件都使用完全相同的设置但不同的连接字符串。

调整我的数据库的发布设置(这有规律地发生,因为我对 SSDT 还是有点陌生​​)是最烦人的,但我还没有找到解决这个问题的方法,因为我无法将转换应用到像我一样将配置文件发布到 ASP.NET 项目中的 web.config 文件。我什至尝试安装 Visual Studio SlowCheetah 插件,但它似乎不适用于 SSDT 项目,因为右键单击发布配置文件时不会出现应用转换的选项。

我不希望我的团队在将数据库部署到开发或 QA 环境时不得不考虑手动输入连接详细信息。有没有什么方法可以设置主发布配置文件或以其他方式指定一组共享设置,这样我就不必管理 20 个几乎相同的发布配置文件??

编辑: 使用 SAS 的回答,我能够为我的 .sqlproj 文件拼凑出以下 XML:

  <PropertyGroup>
    <PublishProfileDir>$(ProjectDir)Publish Profiles\</PublishProfileDir>
    <TemplatePublishProfile>$(PublishProfileDir)Baseline\publish.xml</TemplatePublishProfile>
  </PropertyGroup>
  <Target Name="CopyXml" AfterTargets="Build">
    <Copy SourceFiles="$(TemplatePublishProfile)" DestinationFolder="$(PublishProfileDir)Dev"/>
    <Copy SourceFiles="$(TemplatePublishProfile)" DestinationFolder="$(PublishProfileDir)Qa"/>
  </Target>
  <ItemGroup>
    <DevPublishUpdates Include="ConfigUpdates">
      <XPath>/msb:Project/msb:PropertyGroup/msb:TargetDatabaseName</XPath>
      <NewValue>CountyRecordsDev</NewValue>
    </DevPublishUpdates>
    <DevPublishUpdates Include="ConfigUpdates">
      <XPath>/msb:Project/msb:PropertyGroup/msb:DeployScriptFileName</XPath>
      <NewValue>CountyRecords.Dev.Sql</NewValue>
    </DevPublishUpdates>
  </ItemGroup>
  <Target Name="UpdateXml" AfterTargets="CopyXml">
    <Message Text="Editing Derived Xml Publish Profiles" Importance="high" />
    <XmlPoke Namespaces="&lt;NamespacePrefix='msb'Uri='http://schemas.microsoft.com/developer/msbuild/2003'/&gt;"
        XmlInputath="$(PublishProfileDir)Dev\publish.xml" 
        Query="%(DevPublishUpdates.XPath)" 
        Value="%(DevPublishUpdates.NewValue)" />
  </Target>

唯一的缺点是我的所有发布配置文件似乎都需要一个单独的文件夹,以防止一个转换覆盖另一个转换,我似乎无法找到一种方法来简单地覆盖现有文件。对于 XmlPoke,命名空间属性对于操作至关重要。我从 Sayed Ibrahim Hashimi 的 this blog post 那里了解了更多关于这个过程的信息。

我们正在使用一个模板 xml 文件,该文件作为发布的前一步自动复制,用于我们所有的目标,因此任何更改只需要在模板中进行。目标服务器名称在创建发布 xml 文件时动态替换。为此,我们还必须修改 xaml。我们在公共项目文件中使用 Copy 和 XMLPoke 标签,它们包含在我们的项目文件中。这需要一些工作,但效果很好。

编辑:我在下面粘贴了一些代码来尝试解释,这只是原始代码的一部分,但我希望它足以让大家开始:

这部分内容在我们的公用文件中(SQLCommonInclude.proj):

<Target Name="CreatePublishXMLFile">
 <PropertyGroup>
  <VersionNumber Condition="'$(VersionNumber)'==''">Local Build</VersionNumber>
  <CurrentDate>$([System.DateTime]::Now.ToString(yyyy-MM-dd HH:mm:ss))</CurrentDate>
  <SqlPublishProfilePath Condition="'$(SqlPublishProfilePath)'==''">Publish$(TargetServerParam).publish.xml</SqlPublishProfilePath>
  <TargetXMLFile>$(ProjectDir)Publish$(TargetServerParam).publish.xml</TargetXMLFile>
  <ChangeSets Condition="'$(ChangeSets)'==''">Unknown</ChangeSets>
 </PropertyGroup>
 <XmlPoke XmlInputPath="$(TargetXMLFile)" Query="/*[local-name()='Project']/*[local-name()='PropertyGroup']/*[local-name()='TargetConnectionString']" Value="Data Source=$(TargetServerParam)%3BIntegrated Security=True%3BPooling=False" />
 <XmlPoke XmlInputPath="$(TargetXMLFile)" Query="/*[local-name()='Project']/*[local-name()='PropertyGroup']/*[local-name()='TargetDatabaseName']" Value="$(ProjectName)" />
 <XmlPoke XmlInputPath="$(TargetXMLFile)" Query="/*[local-name()='Project']/*[local-name()='ItemGroup']/*[local-name()='SqlCmdVariable'][@Include='ChangeSets']/*[local-name()='Value']" Value="$(ChangeSets)" />
</Target>

然后为每个目标服务器重复调用:

<Target Name="CreateAllPublishXMLFiles">
 <MSBuild Projects="$(MSBuildProjectFile)" Targets="CreatePublishXMLFile" Properties="TargetServerParam=OURSERVER1" />
 <MSBuild Projects="$(MSBuildProjectFile)" Targets="CreatePublishXMLFile" Properties="TargetServerParam=OURSERVER2" />
</Target>

在每个项目文件中,我们包含并调用公共代码:

<Import Project="$(SolutionDir)SQLCommonInclude.proj" />
<Target Name="BeforeBuild" DependsOnTargets="CreateAllPublishXMLFiles">

然后,在 Post-部署脚本中,我们像这样设置扩展属性:

IF NOT EXISTS (SELECT NULL FROM SYS.EXTENDED_PROPERTIES WHERE class_desc = 'DATABASE' AND name = 'SSDT ChangeSets')
EXEC sp_addextendedproperty @name = N'SSDT ChangeSets', @value = '';
EXEC sp_updateextendedproperty @name = N'SSDT ChangeSets', @value =  '$(ChangeSets)';