如何使Database-> SQL Project的'Schema Compare'尊重SQL-CMD变量

Tom*_*ord 7 sql schema database-project schema-compare visual-studio-2013

我有一个带有2个SQL项目DB1,DB2的Visual Studio 2013解决方案.

DB1有一个引用DB2的存储过程.

如果我在程序中使用.dacpac和同义词

SELECT * FROM [$(DB2)].[dbo].[Table1]
Run Code Online (Sandbox Code Playgroud)

然后将数据库中的Schema与SQL Project进行比较错误地将上述内容检测为更改,因为它不处理变量/同义词.

相反,我使用

SELECT * FROM DB2.[dbo].[Table1]
Run Code Online (Sandbox Code Playgroud)

并将存储过程构建类型更改为(以便项目构建)然后从数据库到Proejct 进行架构比较**将"看不到"我的项目中的存储过程并在每个SQL数据库项目中添加新的过程相比

在模式比较后,我现在将看到

  • DB1
    • DBO
      • 存储过程
        • sp_myStoredProcedure.sql
        • sp_myStoredProcedure1.sql
        • sp_myStoredProcedure n .sql

其中n =架构比较#!

如果有一种方法可以忽略构建错误SQL7501,那么它应该使用第二个选项,但它似乎不能被忽略.

另一种解决方案是保存模式比较并手动选择跳过所有引用DB2的过程但是我想检测这些过程中的更改.

这似乎是一个简单而常见的用例.有人为这个设计缺陷提出了解决方法吗?

更新

在测试了凯文的答案之后,我已经确定了为什么我的一些观点没有正确处理SC.他的答案在技术上是正确的:

如果你在DB1中有一个视图:

SELECT * FROM DB1.dbo.Table1 T1
INNER JOIN DB2.dbo.Table2 T2 
ON T2.Field1 = T1.Field1
Run Code Online (Sandbox Code Playgroud)

并在您的DB1 SQL Project中原始(没有自引用DB1)

SELECT * FROM dbo.Table1 T1
INNER JOIN [$(DB2)].dbo.Table2 T2 
ON T2.Field1 = T1.Field1
Run Code Online (Sandbox Code Playgroud)

模式比较将无法正确替换变量并识别更改:[$(DB2)] - > $(DB2)

问题是自引用DB1.dbo.Table,在我的情况下,已插入大量连接的一半,其中许多是DB2引用.

这会导致SC错误地将所有[$(DB2)]标记为更改.可能是因为数据库sql没有在VS中"构建"并恢复到文本比较.

所以这不是一个真正的错误,但对于没有手动比较SQL的每一行的开发人员而言,这是一个令人困惑的结果.

我认为这个问题可以扩展到以下几点:

每次数据库SQL不构建SQL时,CMD变量都不会被解析,并且会导致错误,这些错误可能会掩盖原始构建失败.

我还必须补充说,在我的情况下,DB2也引用了DB1!

这可能是无法正确报告错误的部分原因.

最后,为了避免循环依赖(项目不能互相引用),我使用Project Reference构建了引用DB2的DB1,但检查了"引用项目中的supress构建错误".DB2没有构建,因为它引用了DB1.

然后,一旦DB1构建,我在bin文件夹中使用输出DACPAC,将其复制到另一个位置,并在DB2中引用DB1 DACPAC.现在任何时候DB1更改我必须重建将DACPAC复制到此文件夹.幸运的是,这不会改变太多.

整个过程非常混乱,SQL项目应该允许彼此引用(具有远程错误抑制),但最终我设法得到2个相互引用的db,并且所有同义词和模式都比较兼容!

它只用了2天的奋斗!

https://connect.microsoft.com/VisualStudio/feedback/details/1291555

Kev*_*ane 6

通过更改"数据库项目属性"中的"SQLCMD变量默认"或"本地"设置,可以避免此问题.行为是: - 如果定义了Local值,则这是Schema Compare中使用的值 - 如果未定义Local值,则将使用Default值.因此,更新Local值以匹配引用的数据库名称,重建和执行新的模式比较应该可以解决此问题.

SQLCMD变量设置 - 本地覆盖默认值 如果您希望定位多个数据库,则现在最好的选择是根据您的配置为"本地"值设置不同的值.这意味着:

  1. 您可以在Build - > Configuration Manager对话框中为每个目标创建一个新的Solution Configuration.这允许您更改某些设置,并使它们因配置而异 Configuration Manager  - 创建新配置
  2. 您编辑应该位于解决方案基础中的projectname.sqlproj.user文件.它包含数据库的Local值,您可以根据配置更改值.在我的示例中,我只有一个变量$(DB2),并且这映射到用户设置中的SqlCmdVar__1设置.我改变了:

    调试

至:

<SqlCmdVar__1 Condition=" '$(Configuration)' == 'Debug' ">Debug</SqlCmdVar__1>
<SqlCmdVar__1 Condition=" '$(Configuration)' == 'Release' ">Release</SqlCmdVar__1>
Run Code Online (Sandbox Code Playgroud)

正如您所看到的,这意味着在Debug配置中,它将具有不同的值来释放.在现实世界中,您可能会为每个要定位的服务器创建一个配置

这比理想的更麻烦,但它确实解决了您的问题,并且是目前工具的最佳方式.

更新:要解决数据库项目之间循环依赖关系的潜在问题,您应该使用Composite Projects.基本过程是:

  • 创建"DB1_Core"和"DB2_Core"项目.将其他数据库引用的对象放在Core项目中
  • 在DB1项目中,将"DB1_Core"添加为"Same Database"参考.这将确保在使用"Include Composite Objects = true"发布时,您的DB1项目就像以前一样发布 - 将包含所有Core对象.
  • 对DB2项目执行相同的操作
  • DB1应该只需要对DB2_Core的引用,DB2引用DB1_Core.这打破了循环依赖关系并允许您安全地构建.

这是一种最佳实践,遵循与C#和其他项目类型类似的模式.有一个关于复合项目的演示文稿 - 链接在这里SSDT博客上.