如何防止 SqlPackage.exe 在部署 dacpac 时删除和重新创建约束?

How can I prevent SqlPackage.exe from dropping and re-creating constraints when deploying a dacpac?

我有一个 Visual Studio sql 项目,其 table 定义如下:

CREATE TABLE [dbo].[Hoerses]
(
   [HoersId] INT NOT NULL PRIMARY KEY,
   [DatePurchased] datetime NOT NULL CONSTRAINT [DF_Hoerses_DatePurchased] DEFAULT DATETIMEFROMPARTS(1985,01,01,0,0,0,0)
)

当我使用 "Script" 命令瞄准一个预先存在的 SQL 数据库时

sqlpackage.exe /Action:Script /SourceFile:DatabaseProject1.dacpac  /Profile:publish.xml /OutputPath:deployscript_test.sql /TargetPassword:redacted

然后我得到以下生成的 SQL,即使约束在前后具有相同的名称和定义:

PRINT N'Dropping [dbo].[DF_Hoerses_DatePurchased]...';


GO
ALTER TABLE [dbo].[Hoerses] DROP CONSTRAINT [DF_Hoerses_DatePurchased];


GO
PRINT N'Creating [dbo].[DF_Hoerses_DatePurchased]...';


GO
ALTER TABLE [dbo].[Hoerses]
    ADD CONSTRAINT [DF_Hoerses_DatePurchased] DEFAULT DATETIMEFROMPARTS(1985,01,01,0,0,0,0) FOR [DatePurchased];


GO
PRINT N'Update complete.';


GO

(我主要担心试图阻止这种多余的重新创建是因为我偶尔会在实际 deployments/publishing 期间尝试删除约束时看到 "Lock request time out period exceeded." 错误)

问题显然出在 DATETIMEFROMPARTS 的使用上。

如果我改为将 table 声明为

CREATE TABLE [dbo].[Hoerses]
(
   [HoersId] INT NOT NULL PRIMARY KEY,
   [DatePurchased] datetime NOT NULL CONSTRAINT [DF_Hoerses_DatePurchased] DEFAULT '1985-01-01'
) 

然后 SqlPackage.exe 不再尝试删除和重新添加约束。

Dacpac 部署的工作原理是将数据库架构的 XML 结构与您的 VS 项目中的结构进行比较。 有时,此过程会因句法细节而混淆,从而导致如您所描述的那样重复更改。 我的建议是您转到已部署的数据库,编写出有问题的对象的脚本,然后将其粘贴回该对象的 Visual Studio 文件的实现中。这解决了明显的差异,因此部署不再被误认为它需要实施更改。

我还找到了一篇对我有帮助的文章。 http://johnnydba.blogspot.com/2015/07/are-your-vs-database-projects-dropping.html

文章中提到的可能存在的问题基本上就是这些:

  1. 某些系统函数在 SQL 服务器中以小写形式表示,例如 getdate()sysutcdatetime()getutcdate()newid()
myDate datetime2 DF_myTable_myDate DEFAULT(getdate()) NOT NULL
  1. 默认约束中的标量数值需要用双括号括起来((0)),但我注意到字符串值不需要。
myBit bit DF_myTable_myBit DEFAULT((0)) NOT NULL
  1. 过滤索引和检查约束条件必须用括号括起来(),列名必须在方括号中,比较运算符左右不能有空格
-- Column check
CONSTRAINT CH_myTable_someCheck CHECK ([myColumn]>(0))
-- Function check
CONSTRAINT CH_myTable_anotherCheck CHECK ([dbo].[someFunc]([myColumn],[myAnotherColumn])=(1))
  1. 有些列必须用方括号括起来[]

这是用于约束的关键字大小写。

在您的默认设置中,对 getdate()newid() 等关键字使用小写字母。

将始终删除这些约束:

CREATE TABLE [dbo].[APPLICATION_ERROR]

(
    [ERROR_ID]      UNIQUEIDENTIFIER
        CONSTRAINT [CT_ERROR_ID] DEFAULT (NEWID()) NOT NULL,
    [ERROR_DATE]    DATETIME
        CONSTRAINT [CT_ERROR_DATE] DEFAULT (GETDATE()) NULL
);

这些不会:

CREATE TABLE [dbo].[APPLICATION_ERROR]

(
    [ERROR_ID]      UNIQUEIDENTIFIER
        CONSTRAINT [CT_ERROR_ID] DEFAULT (newid()) NOT NULL,
    [ERROR_DATE]    DATETIME
        CONSTRAINT [CT_ERROR_DATE] DEFAULT (getdate()) NULL
);

如果约束是数字,你应该使用双括号:

   [LABOR_AMOUNT] MONEY
     CONSTRAINT [DF_LABOR_AMOUNT]
                DEFAULT ((0)) NULL

您还应该将此添加到您的发布配置文件中,但这不是问题的核心:

<IgnoreKeywordCasing>True</IgnoreKeywordCasing>