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

标签 sql visual-studio-2013 schema database-project schema-compare

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

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

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

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

然后比较从数据库到 SQL 项目的架构错误地将上述内容检测为更改,因为它不处理变量/同义词。

如果我使用

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

并将存储过程构建类型更改为(以便项目构建),然后架构比较从数据库到项目**时将“看不到”在我的项目中存储过程,并在每次比较时向 SQL 数据库项目添加一个新过程

经过架构比较后,我现在将看到

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

其中 n = 比较模式的数量!

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

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

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

更新

测试 Kevin 的答案后,我已经确定了为什么 SC 无法正确处理我的一些 View 。然而,他的回答在技术上是正确的:

如果您在 DB1 中有 View :

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 中“构建”并恢复为文本比较。

所以这并不是真正的错误,但对于不手动比较 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,但检查了“抑制引用项目中的构建错误”。 DB2 没有构建,因为它引用了 DB1。

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

这整个过程非常复杂,SQL 项目应该允许相互引用(通过远程错误抑制),但无论如何,最终我设法获得了 2 个相互引用的数据库,并且所有数据库都具有同义词和模式比较兼容!

而且只用了2天的奋斗时间!

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

最佳答案

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

SQLCMD Variable settings - local overrides Default 如果您希望定位多个数据库,那么现在最好的选择是根据您的配置为“本地”值设置不同的值。这意味着:

  1. 您可以在“构建”->“配置管理器”对话框中为每个目标创建一个新的解决方案配置。这允许您更改一些设置并让它们根据配置而变化 Configuration Manager - create new Configuration
  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”作为“同一数据库”引用。这将确保在使用“Include Composite Objects = true”进行发布时,您的 DB1 项目会像以前一样发布 - 所有核心对象都将被包含在内。
  • 对 DB2 项目执行相同的操作
  • DB1 应该只需要对 DB2_Core 的引用,而 DB2 则引用 DB1_Core。这打破了循环依赖并允许您安全地构建。

这是最佳实践,遵循与 C# 和其他项目类型类似的模式。有一个涵盖复合项目的演示 - 链接位于 SSDT blog here .

关于sql - 如何使数据库->SQL 项目的 'Schema Compare' 尊重 SQL-CMD 变量,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/29969634/

相关文章:

SQL LEFT JOIN、Average 和 WHERE

colors - Visual Studio 2013 不突出显示 typescript 文件

mysql - 你如何构建一个允许投票的数据库,类似于 stackoverflow 的做法?

mysql - 将 varchar 值 '19500.00' 转换为数据类型 int 时转换失败

sql - 使用 qt 连接到 SQL Server

sql - 为什么 Postgres EXPLAIN ANALYZE execution_time 与我运行实际查询时不同?

vb.net - 在 Visual Studio 中显示时,Access 数据库记录未保持正确的顺序

mysql - 无法使用 EF6 和 MYSQL 生成实体

Java Hibernate将对象保存在一个数据库中的不同模式中

database - 为什么很少有完整的数据库模式在线样本?