使用SSDT发布(.dacpac)部署非null外键架构更新



我一直在使用.dacpacs将数据库更新部署到我们的各种环境中。我发现了一个导致发布特定更新失败的场景。

我需要添加一个新表dbo.Supplier,并向另一个具有引用新表的不可为null的foriegn键的表dbo.PickZone添加一列。SSDT项目中的模式反映了这一点,为了准备新的NOT NULL列,我有以下预部署脚本;

IF object_id('dbo.Supplier') IS NULL
BEGIN
    CREATE TABLE [dbo].[Supplier]
    (
        [SupplierId] INT IDENTITY(1,1) NOT NULL,
        [Name] varchar(50) NOT NULL,
        CONSTRAINT [PK_Supplier] PRIMARY KEY CLUSTERED ([SupplierId])
    );
    SET IDENTITY_INSERT [dbo].[Supplier] ON;
    INSERT INTO Supplier (SupplierId, Name) VALUES (1, 'Default Supplier')
    SET IDENTITY_INSERT [dbo].[Supplier] OFF;
    ALTER TABLE dbo.PickZone ADD SupplierId int NULL;
    UPDATE PickZone SET SupplierId = 1
END

上面的脚本更新架构和数据,以确保发布发生时(我使用的是sqlpackage.exe(,当它将foriegn密钥约束应用于dbo.PickZone.SupplierId:时不会失败

CREATE TABLE [dbo].[PickZone]
(
    [PickZoneId] INT IDENTITY (1, 1) NOT NULL PRIMARY KEY, 
    [Name] VARCHAR(50) NOT NULL,
    [SupplierId] INT NOT NULL,
    CONSTRAINT [FK_PickZone_Supplier] FOREIGN KEY ([SupplierId]) REFERENCES [dbo].[Supplier] ([SupplierId])
)

问题是,vs2012Publish和sqlpackage.exe deploy似乎都准备了所需的架构更新,然后执行预部署脚本,然后执行架构更新-由于预部署脚本进行架构更改,这些更新现在不同步。

这会导致架构发布再次尝试添加表和列,并导致其失败。

很明显,我可以更改我的部署过程,在dacpac部署之外执行这些类型的准备脚本,但我有点希望dacpac负责所有架构更改。。。

有人知道如何发布dacpac来满足这种类型的更新吗?

我将描述我的解决方案。我们将使用部署dacpacs的sqlpackage工具。该工具支持许多参数。其中之一是GenerateSmartDefaults。请参见此处。

正如我所认为的,部署前脚本不必包含模式修改。只有SELECT、INSERT、UPDATE和DELETE语句。部署后脚本也是。

  1. 修改数据库架构(添加不带默认值的非null列或作为外键(
  2. 在部署后脚本中,为该列添加UPDATE语句并构建dacpac
  3. 使用SqlPackage工具部署此dacpac,如下所示:SqlPackage.exe/Action:Publish/SourceFile:your.dacpac/TargetServerName:serverName/TargetDatabaseName:databaseName/p:GenerateSmartDefaults=True

我认为您试图以错误的顺序执行此操作。默认情况下,SSDT在整个更新完成之前不会检查约束,即使在部署后脚本之后也是如此。这意味着您应该能够在项目中添加具有默认值和约束的表,在部署后脚本中发布数据插入/更新,并在完成所有操作后让SSDT启用FK约束。

如果你对此感到不舒服,你可以按照以下顺序进行:

  • 创建表格
  • 在部署后脚本中填充表
  • 快照该架构
  • -----------------
  • 添加列(使用默认值(和FK约束
  • 快照该架构
  • -----------------
  • 发布快照A
  • 发布快照B

我认为,在大多数情况下,如果您的选项设置正确,以便在执行其他操作之后启用检查约束,则不必经历第二个过程。

最新更新