http://blog.danskingdom.com/using-msbuild-to-publish-a-vs-2012-ssdt-sqlproj-database-project-the-same-way-as-a-vs-2010-dbproj-database-project/

Post and code updated on March 21, 2013, and again on March 22, 2013.

We recently upgraded from VS (Visual Studio) 2010 to VS 2012, and with it had to upgrade our .dbproj database project to a .sqlproj.  When making the switch I realized that .sqlproj database projects do not support specifying the database to deploy to as MSBuild command line arguments; instead you have to pass in the path to an xml file that has the necessary information.

So with the old .dbproj database project, you could deploy it to a database using:

MSBuild /t:Deploy /p:TargetDatabase="[DbName]";TargetConnectionString="Data Source=[Db.Server];Integrated Security=True;Pooling=False" /p:DeployToDatabase="True" "[PathToBranch]Database\Database.dbproj"

But with the new .sqlproj database project you have to do:

MSBuild /t:Publish /p:SqlPublishProfilePath="myPublishFile.publish.xml" "[PathToBranch]Database\Database.sqlproj"

Where “myPublishFile.publish.xml” contains the database server and name to publish to.

One other minor thing to note is that it is called “deploying” the database with .dbproj, and is called “publishing” the database with .sqlproj; so when I say Deploy or Publish, I mean the same thing.

We use TFS at my organization and while making new builds for our Test environment, we have the build process deploy the database solution to our various Test databases.  This would mean that for us I would either need to:

1 – create a new [DbName].publish.xml file for each database, check it into source control, and update the build template to know about the new file, or

2 – update the file contents of our myPublishFile.publish.xml file dynamically during the build to replace the Database Name and Server in the file before publishing to the database (i.e. read in file contents, replace string, write file contents back to file, publish to DB, repeat).

Option 1 means more work every time I want to add a new Test database to publish to.  Option 2 is better, but still means having to update my TF Build template and create a new activity to read/write the new contents to the file.

Instead, there is a 3rd option, which is to simply add the code below to the bottom of the .sqlproj file.  This will add some new MSBuild targets to the .sqlproj that will allow us to specify the database name and connection string using similar MSBuild command line parameters that we used to deploy the .dbproj project.

The code presented here is based on this post, but the author has closed the comments section on that post and has not replied to my emails about the bugs in his code and example, so I thought I would share my modified and enhanced solution.

  <!--
Custom targets and properties added so that we can specify the database to publish to using command line parameters with VS 2012 .sqlproj projects, like we did with VS 2010 .dbproj projects.
This allows us to specify the MSBuild command-line parameters TargetDatabaseName, and TargetConnectionString when Publishing, and PublishToDatabase when Building.
I also stumbled across the undocumented parameter, PublishScriptFileName, which can be used to specify the generated sql script file name, just like DeployScriptFileName used to in VS 2010 .dbproj projects.
Taken from: http://blog.danskingdom.com/using-msbuild-to-publish-a-vs-2012-ssdt-sqlproj-database-project-the-same-way-as-a-vs-2010-dbproj-database-project/
-->
<PropertyGroup Condition="'$(TargetDatabaseName)' != '' Or '$(TargetConnectionString)' != ''">
<PublishToDatabase Condition="'$(PublishToDatabase)' == ''">False</PublishToDatabase>
<TargetConnectionStringXml Condition="'$(TargetConnectionString)' != ''">
&lt;TargetConnectionString xdt:Transform="Replace"&gt;$(TargetConnectionString)&lt;/TargetConnectionString&gt;
</TargetConnectionStringXml>
<TargetDatabaseXml Condition="'$(TargetDatabaseName)' != ''">
&lt;TargetDatabaseName xdt:Transform="Replace"&gt;$(TargetDatabaseName)&lt;/TargetDatabaseName&gt;
</TargetDatabaseXml>
<TransformPublishXml>
&lt;Project xmlns:xdt="http://schemas.microsoft.com/XML-Document-Transform" xmlns="http://schemas.microsoft.com/developer/msbuild/2003"&gt;
&lt;PropertyGroup&gt;$(TargetConnectionStringXml)$(TargetDatabaseXml)&lt;/PropertyGroup&gt;
&lt;/Project&gt;
</TransformPublishXml>
<SqlPublishProfilePath Condition="'$([System.IO.Path]::IsPathRooted($(SqlPublishProfilePath)))' == 'False'">$(MSBuildProjectDirectory)\$(SqlPublishProfilePath)</SqlPublishProfilePath>
<!-- In order to do a transform, we HAVE to change the SqlPublishProfilePath -->
<TransformOutputFile>$(MSBuildProjectDirectory)\Transformed_$(TargetDatabaseName).publish.xml</TransformOutputFile>
<TransformScope>$([System.IO.Path]::GetFullPath($(MSBuildProjectDirectory)))</TransformScope>
<TransformStackTraceEnabled Condition="'$(TransformStackTraceEnabled)'==''">False</TransformStackTraceEnabled>
</PropertyGroup>
<Target Name="AfterBuild" Condition="'$(PublishToDatabase)'=='True'">
<CallTarget Targets="Publish" />
</Target>
<UsingTask TaskName="ParameterizeTransformXml" AssemblyFile="$(MSBuildExtensionsPath)\Microsoft\VisualStudio\v$(VisualStudioVersion)\Web\Microsoft.Web.Publishing.Tasks.dll" />
<Target Name="BeforePublish" Condition="'$(TargetDatabaseName)' != '' Or '$(TargetConnectionString)' != ''">
<Message Text="TargetDatabaseName = '$(TargetDatabaseName)', TargetConnectionString = '$(TargetConnectionString)', PublishScriptFileName = '$(PublishScriptFileName)', Transformed Sql Publish Profile Path = '$(TransformOutputFile)'" Importance="high" />
<!-- If TargetDatabaseName or TargetConnectionString, is passed in then we use the tokenize transform to create a parameterized sql publish file -->
<Error Condition="!Exists($(SqlPublishProfilePath))" Text="The SqlPublishProfilePath '$(SqlPublishProfilePath)' does not exist, please specify a valid file using msbuild /p:SqlPublishProfilePath='Path'" />
<ParameterizeTransformXml Source="$(SqlPublishProfilePath)" IsSourceAFile="True" Transform="$(TransformPublishXml)" IsTransformAFile="False" Destination="$(TransformOutputFile)" IsDestinationAFile="True" Scope="$(TransformScope)" StackTrace="$(TransformStackTraceEnabled)" SourceRootPath="$(MSBuildProjectDirectory)" />
<PropertyGroup>
<SqlPublishProfilePath>$(TransformOutputFile)</SqlPublishProfilePath>
</PropertyGroup>
</Target>

So after adding this code at the bottom of the .sqlproj file (above the </Project> tag though), you can now build and publish the database solution from the MSBuild command line using:

MSBuild /t:Build /p:TargetDatabaseName="[DbName]";TargetConnectionString="Data Source=[Db.Server];Integrated Security=True;Pooling=False" /p:PublishToDatabase="True" /p:SqlPublishProfilePath="Template.publish.xml" "[PathToBranch]\Database\Database.sqlproj"

Here you can see the 3 new parameters that we’ve added being used: TargetDatabaseName, TargetConnectionString, and PublishToDatabase.

When the TargetDatabaseName or TargetConnectionString parameters are provided we generated a new transformed .publish.xml file, which is the same as the provided “Template.publish.xml” file, but with the database and connection string values replaced with the provided values.

The PublishToDatabase parameter allows us to publish to the database immediately after the project is built; without this you would have to first call MSBuild to Build the database project, and then call MSBuild again to Publish it (or perhaps using “/t:Build;Publish” would work, but I didn’t test that).

If you want to simply publish the database project without building first (generally not recommended), you can do:

MSBuild /t:Publish /p:TargetDatabaseName="[DbName]";TargetConnectionString="Data Source=[Db.Server];Integrated Security=True;Pooling=False" /p:SqlPublishProfilePath="Template.publish.xml" "[PathToBranch]\Database\Database.sqlproj"

Be careful though, since if you don’t do a Build first, any changes that have been made since the last time the .sqlproj file was built on your machine won’t be published to the database.

Notice that I still have to provide a path to the template publish.xml file to transform, and that the path to this file is relative to the .sqlproj file (in this example the Template.publish.xml and .sqlproj files are in the same directory).  You can simply use one of the publish.xml files generated by Visual Studio, and then the TargetDatabaseName and TargetConnectionString xml element values will be replaced with those given in the command line parameters.  This allows you to still define any other publish settings as usual in the xml file.

Also notice that the PublishToDatabase parameter is only used when doing a Build, not a Publish; providing it when doing a Publish will not hurt anything though.

While creating my solution, I also accidentally stumbled upon what seems to be an undocumented SSDT parameter, PublishScriptFileName.  While the DeployScriptFileName parameter could be used in VS 2010 .dbproj projects to change the name of the generated .sql file, I noticed that changing its value in the .publish.xml file didn’t seem to have any affect at all (so I’m not really sure why Visual Studio puts it in there).  I randomly decided to try passing in PublishScriptFileName from the command line, and blamo, it worked!  I tried changing the <DeployScriptFileName> element in the .publish.xml file to <PublishScriptFileName>, but it still didn’t seem to have any effect.

So now if I wanted to deploy my database project to 3 separate databases, I could do so with the following code to first Build the project, and the Publish it to the 3 databases:

MSBuild /t:Build "[PathToBranch]\Database\Database.sqlproj"
MSBuild /t:Publish /p:TargetDatabaseName="[DbName1]";TargetConnectionString="Data Source=[Db.Server];Integrated Security=True;Pooling=False" /p:PublishScriptFileName="[DbName1].sql" /p:SqlPublishProfilePath="Template.publish.xml" "[PathToBranch]\Database\Database.sqlproj"
MSBuild /t:Publish /p:TargetDatabaseName="[DbName2]";TargetConnectionString="Data Source=[Db.Server];Integrated Security=True;Pooling=False" /p:PublishScriptFileName="[DbName2].sql" /p:SqlPublishProfilePath="Template.publish.xml" "[PathToBranch]\Database\Database.sqlproj"
MSBuild /t:Publish /p:TargetDatabaseName="[DbName3]";TargetConnectionString="Data Source=[Db.Server];Integrated Security=True;Pooling=False" /p:PublishScriptFileName="[DbName3].sql" /p:SqlPublishProfilePath="Template.publish.xml" "[PathToBranch]\Database\Database.sqlproj"

You could also instead just call MSBuild using the Build target with the PublishToDatabase parameter (which might actually be the safer bet); whatever you prefer.  I have found that once the database project is built once, as long as no changes are made to it then subsequent “builds” of the project only take a second or two since it detects that no changes have been made and skips doing the build.

If you have any questions or feedback, let me know.

Happy coding!

Using MSBuild to publish a VS 2012 SSDT .sqlproj database project的更多相关文章

  1. Headless MSBuild Support for SSDT (*.sqlproj) Projects

    http://sqlproj.com/index.php/2012/03/headless-msbuild-support-for-ssdt-sqlproj-projects/ Update: bre ...

  2. Headless MSBuild Support for SSDT (*.sqlproj) Projects [利用msbuild自动化部署 .sqlproj]- 摘自网络

    Update: breaking change: http://sqlproj.com/index.php/2012/10/dacfx-sept-2012-updates-break-headless ...

  3. use MSBuild cmd to build and deploy the database project.

    You can use the below command to implement it. SET TargetDBName="Database name" SET DataBa ...

  4. Visual Studio 2012创建SQL Server Database Project提示失败解决方法

    新建一个SQL Server Database Project,提示: Unable to open Database project This version of SQL Server Data ...

  5. vs 2012 InstallShield Limited Edition Project 打包windows服务解析

    最近项目从vs2005 升级到vs2010后,发现新的vs2010 不再带有原来的安装工程项目,导致以前的安装包不可以使用,查找资料后发现微软从vs2010 版本后不再提供自带的安装工程,尝试着利用  ...

  6. 如何使用SSDT进行SQL数据库的自动化部署到生产环境和版本控制

    简介 在开发过程,我们常常会遇到数据库环境部署的问题,当部署正式环境中,数据库产生的多文件脚本在管理上就容易出现混乱,特别是你还没有权限访问正式环境的情况,就更为困难.SSDT为我们提供了很好的解决方 ...

  7. [独孤九剑]持续集成实践(二)– MSBuild语法入门

    本系列文章包含: [独孤九剑]持续集成实践(一)- 引子 [独孤九剑]持续集成实践(二)– MSBuild语法入门 [独孤九剑]持续集成实践(三)- Jenkins安装与配置(Jenkins+MSBu ...

  8. 在.NET 环境中实现每日构建(Daily Build)--ccnet,MSBuild篇(转载)

    每日构建,对我们团队来说一个全新的概念.随着项目开发的进展,在开发过 程需要及时反馈一些BUG和功能要求的处理情况.而在这种情况下每天或隔一段时间Build一个版本,工作量还是比较大的,所以就特别有必 ...

  9. 用MSBuild和Jenkins搭建持续集成环境(1)

     http://www.infoq.com/cn/articles/MSBuild-1 你或其他人刚刚写完了一段代码,提交到项目的版本仓库里面.但等一下,如果新提交的代码把构建搞坏了怎么办?万一出现编 ...

随机推荐

  1. linux文件创建、查看、编辑命令

    一.创建文件命令 1.touch命令 linux的touch命令不常用,一般在使用make的时候可能会用到,用来修改文件时间戳,或者新建一个不存在的文件.touch   [-acm][-r   ref ...

  2. 让wego微购购物分享系统采集拍拍数据功能之腾讯paipai功能采集插件

    wego是一款很不错的导购系统,无论前后台设计风格和功能都还不错,可有时我们的确需要一些自定义的功能,毕竟万千世界,大家都做一样的东西,采集同样的数据,能不烦吗?哈哈,今天就奉献上一个wego拍拍采集 ...

  3. js鼠标滑轮滚动事件绑定(兼容主流浏览器)

    /** Event handler for mouse wheel event. *鼠标滚动事件 */ var wheel = function(event) { var delta = 0; if ...

  4. 论meta name= viewport content= width=device-width initial-scale=1 minimum-scale=1 maximum-scale=1的作用

    一.先明白几个概念 phys.width: device-width: 一般我们所指的宽度width即为phys.width,而device-width又称为css-width. 其中我们可以获取ph ...

  5. thinkphp框架3.2的cookie删除问题记录

    在使用框架删除cookie时,发现cookie(null)不起作用.后来查看官网相关信息,看到了讨论http://www.thinkphp.cn/bug/2602.html

  6. Spring的特点

    创始人:Rod Johson1.特点: a:方便解耦和,简化开发,提升性能 b:AOP面向切面的编程 c:声明式事务支持 d:方便程序的调式 e:方便集成各大优秀的框架 f:java源代码学习的典范 ...

  7. vue 解决display与 transition冲突

    下边是vue的源码 var raf = inBrowser && window.requestAnimationFrame; var waitForTransitionStart = ...

  8. Json的语法及使用方法

    Json的语法及使用方法 Json(JavaScript Object Notation)对象表示标识,是一种轻量级的数据交换语言,比XML更容易解析,独立于语言和平台. 语法规则: 对象用{}保存 ...

  9. 标签data-*属性使用

    <div class="page_index" style="margin-top:20px;"> <span id="showPa ...

  10. git-配置公司账号

    1.初始化配置 git config --global user.name " abc" git config --global user.email "abc@123. ...