我在Visual Studio 2013中使用SSDT。
我为开发服务器创建了一些发布前和发布后脚本。预部署脚本从表中清空数据并重新设置所有自动标识字段。部署后脚本使用静态和示例数据填充表。
现在我需要将数据库发布到我们的登台和实时数据库服务器。我为这些服务器创建了新的“publish.xml”配置文件。但显然我不希望运行相同的前后脚本。
如何根据发布配置文件指定不同的脚本,或使脚本知道目标并执行不同的操作。
我最担心的是发布到实时服务器并意外破坏数据。
提前致谢。
道格
答案 0 :(得分:5)
您有几个选择:
1 - 在对@servername的调用或环境特有的内容中包含您的数据更改,以便您有类似的内容:
if @@servername = 'dev_server'
begin
delete blah
insert blah
end
2 - 你也可以使用sqlcmd变量实现类似的东西,传入一个名为“/ v:DestoryData = true”的变量,然后你可以在你的脚本中引用它。
3 - 不要使用前/后部署脚本,但有自己的运行机制,即使用批处理文件来部署dacpacs并在之前和之后添加对sqlcmd的调用 - 这是在部署时的缺点,对表的更改会导致在预部署之前禁用任何外键,并在部署后重新启用。
4 - 编辑dacpacs,前/后部署脚本只是dacpac中的文本文件,它本质上是一个遵循microsoft打包格式的zip文件,并且有一个.net打包api可以让你修改它。
我认为就是这样,请问是否有任何不清楚的地方:)
编
答案 1 :(得分:4)
我建议使用SQLCMD变量来执行条件脚本。
如果右键单击数据库项目并选择“属性”,则会出现一个选项卡" SQLCMD变量"
输入" $(ServerName)"作为变量和某些东西作为默认值。
然后你需要在XML编辑器中打开你的每个.publish.xml,在PropertyGroup部分之后插入以下代码:
<ItemGroup>
<SqlCmdVariable Include="ServerName">
<Value>[YourVersionOfServer]</Value>
</SqlCmdVariable>
</ItemGroup>
[YourVersionOfServer]应该等于每台服务器上@@ servername的结果。
最终的.publish.xml可能如下所示:
然后,您应该使用以下命令将部署代码中的条件代码包装起来:
if @@servername = '$(ServerName)'
begin
... code for specific server
end
因此,您可以保证正确的代码能够访问正确的服务器
答案 2 :(得分:0)
首先通过右键单击项目并转到属性和“ SQLCMD变量”选项卡来设置SQLCMD变量:
然后为您设置一个文件夹结构,以组织要为特定服务器运行的脚本或要关闭的其他任何事物(例如客户)。每个服务器获得的文件夹。我喜欢将要为该文件夹运行的所有脚本打包到该文件夹中的索引文件中。索引列出了:r命令,后跟应该运行的文件夹中的每个脚本,均按带有数字前缀的文件名进行组织,以便可以控制顺序。
在对所有服务器文件夹进行分组的文件夹中的索引文件中,与列出对每个服务器的索引文件的调用相比,它会执行不同的操作,而是根据基于发布的传入SQLCMD变量切换要运行的索引文件轮廓。使用以下简单代码即可做到这一点:
:r .\$(Customer)\Index.sql
之所以要通过设置文件夹和索引文件来做到这一点,是因为它不仅可以使事情井井有条,而且还允许您在所有文件中使用Go语句。然后,您可以将一个脚本与:r语句一起用于要运行的所有其他脚本,以嵌套您的内心内容。 您可以按照以下方式设置sqlcmd文件来执行此操作,该方法不需要设置文件夹或文件的特定名称,但是需要删除所有GO语句。通过上述方法,您不必删除任何go语句。
if @@servername = '$(ServerName)'
begin
... code for specific server
end
然后,当我右键单击该项目并单击“发布”时,它将构建该项目并弹出以下对话框。我可以通过更改SQLCMD变量来更改要运行的脚本。
我想将最常用的设置保存为单独的发布配置文件,然后只需在解决方案资源管理器中单击它的.xml文件即可返回到它。此过程使一切变得如此简单,无需手动修改xml,只需使用上面显示的“发布数据库”对话框单击“将配置文件另存为”,“加载配置文件”或“创建配置文件”即可。
此外,您可以使用以下powershell脚本生成索引文件:
foreach($directory in (Get-ChildItem -Directory -Recurse) | Get-Item)
{
#skip writing to any index file with ---Ignore in it.
if(-Not ((Test-Path $directory\Index.sql) -and (Get-Content $directory\Index.sql | %{$match = $false}{ $match = $match -or $_ -match "---Ignore" }{$match})))
{
$output = "";
foreach($childitem in (Get-ChildItem $directory -Exclude Index.sql, *.ps1 | Sort-Object | Get-Item))
{
$output= $output + ":r .\" + $childitem.name
if($childitem -is [system.io.directoryinfo])
{
$output = $output + "\Index.sql";
}
$output = $output + "`r`n"
}
Out-File $directory\Index.sql -Encoding utf8 -InputObject $output
}
}
答案 3 :(得分:0)
对于任何想知道您也可以这样做的人:
发布个人资料:
<ItemGroup>
<SqlCmdVariable Include="Environment">
<Value>Dev</Value>
</SqlCmdVariable>
</ItemGroup>
部署后脚本:
if '$(Environment)' = 'Dev'
begin
... code for specific server
end
与“ServerName”语义相比,这种方式对我来说似乎更自然一些。我在尝试使用 @@servername
时也遇到了问题,但不知道为什么。