如何使数据库的 'Schema Compare'->SQL 项目尊重 SQL-CMD 变量

How to make 'Schema Compare' of Database->SQL Project respect SQL-CMD Variables

我有一个 Visual Studio 2013 解决方案,其中包含 2 个 SQL 项目 DB1、DB2。

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

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

SELECT * FROM [$(DB2)].[dbo].[Table1]

然后 将数据库中的模式与 SQL 项目进行比较 错误地将上述检测为更改,因为它不处理 variables/synonyms。

如果我改用

SELECT * FROM DB2.[dbo].[Table1]

并将存储过程构建类型更改为 None(以便项目构建)然后从数据库[=87 进行架构比较 =] 到 Proejct** 将 'not see' 我项目中的存储过程,并在每次比较时向 SQL 数据库项目添加一个新过程

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

  • DB1
    • dbo
      • 存储过程
        • sp_myStoredProcedure.sql
        • sp_myStoredProcedure1.sql
        • sp_myStoredProceduren.sql

其中 n = # 模式比较!

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

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

这似乎是一个简单而常见的用例。有人想出解决此设计缺陷的方法吗?

更新

在测试了 Kevin 的回答后,我确定了为什么我的某些观点无法通过 SC 正确处理。然而,他的回答在技术上是正确的:

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

SELECT * FROM DB1.dbo.Table1 T1
INNER JOIN DB2.dbo.Table2 T2 
ON T2.Field1 = T1.Field1

并在您的 DB1 中 SQL 投影原始文件(没有自我引用 DB1)

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

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

问题是自引用 DB1.dbo.Table,在我的例子中,它已被插入到大量连接的中间位置,其中许多是 DB2 引用。

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

所以这并不是真正的错误,但对于不手动比较 SQL 的每一行的开发人员来说,这是一个令人困惑的结果。

我认为这个问题可以扩展为以下内容:

Any time a Database SQL does not build SQL CMD Variables will not be parsed and will result in errors that may obscure the original build failure.

我还必须补充一点,在我的案例中,DB2 还引用了 DB1!

这可能是无法正确报错的部分原因。

最后,为了避免循环依赖(项目不能相互引用),我使用项目引用构建了引用 DB2 的 DB1,但检查了 'supress build errors in the referenced project'。 DB2 没有构建,因为它引用了 DB1。

然后,一旦构建了 DB1,我就使用了 bin 文件夹中的输出 DACPAC,将其复制到另一个位置,并在 DB2 中引用了该 DB1 DACPAC。现在,每当 DB1 发生更改时,我都必须重建,将 DACPAC 复制到此文件夹。对我来说幸运的是,这不会改变太多。

整个过程非常复杂,SQL 项目应该允许相互引用(远程错误抑制),但不管最后我设法得到 2 个相互引用的数据库,并且所有与同义词和模式比较兼容!

而且只用了2天的奋斗!

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

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

如果您有多个目标数据库,现在最好的选择是根据您的配置为 "Local" 值设置不同的值。这意味着:

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

    调试

收件人:

<SqlCmdVar__1 Condition=" '$(Configuration)' == 'Debug' ">Debug</SqlCmdVar__1>
<SqlCmdVar__1 Condition=" '$(Configuration)' == 'Release' ">Release</SqlCmdVar__1>

如您所见,这意味着在调试配置中它将有一个不同的值要发布。在现实世界中,您可能会为每个目标服务器创建一个配置

这比理想情况更麻烦,但它确实解决了您的问题,并且是使用现有工具的最佳方式。

更新: 要解决数据库项目之间循环依赖的潜在问题,您应该使用复合项目。基本流程是:

  • 创建 "DB1_Core" 和 "DB2_Core" 项目。将其他数据库引用的对象放在Core项目中
  • 在您的 DB1 项目中添加 "DB1_Core" 作为 "Same Database" 引用。这将确保在使用 "Include Composite Objects = true" 发布时,您的 DB1 项目会像以前一样发布 - 所有核心对象都将包括在内。
  • 对 DB2 项目做同样的事情
  • DB1 应该只需要引用 DB2_Core,而 DB2 引用 DB1_Core。这打破了循环依赖并允许您安全地构建。

这是最佳做法,遵循与 C# 和其他项目类型类似的模式。有一个涵盖复合项目的演示文稿 - link 在 SSDT blog here.