使用SSDT发布(.dacpac)来部署非空外键模式更新

5
我一直在使用.dacpac文件将数据库更新部署到各个环境。我发现了一种情况,会导致特定更新的发布失败。
我需要添加一个名为dbo.Supplier的新表,并在另一个表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),当它将外键约束应用于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])
)

问题在于,似乎vs2012发布和sqlpackage.exe部署都会准备所需的模式更新,然后执行预部署脚本,接着执行模式更新——由于预部署脚本进行了模式更改,所以现在这些更新已经不同步了。
这导致模式发布再次尝试添加表格和列,并导致发布失败。
我可以显然地改变我的部署流程,将这些类型的准备脚本执行在dacpac部署之外,但是我希望dacpac负责所有模式更改......
有人知道如何让dacpac发布适应这种类型的更新吗?
2个回答

2
我将描述我的解决方案。 我们将使用sqlpackage工具来部署dacpacs。该工具支持许多参数,其中一个是GenerateSmartDefaults。详见此处
我认为预部署脚本不必包含模式修改,只需要包含SELECT、INSERT、UPDATE、DELETE语句。后部署脚本也是如此。
1. 修改你的数据库模式(添加无默认值或作为外键的非空列)。 2. 在后部署脚本中添加针对此列的UPDATE语句并构建dacpac。 3. 使用SqlPackage工具按以下方式部署该dacpac:sqlpackage.exe /Action:Publish /SourceFile:your.dacpac /TargetServerName:serverName /TargetDatabaseName:databaseName /p:GenerateSmartDefaults=True

1
我认为您正在错误的顺序中尝试执行此操作。默认情况下,SSDT 不会在整个更新完成之前检查约束条件 - 即使在发布后脚本之后。这意味着您只需在项目中添加带有默认值和约束条件的表格,在 Post-Deploy 脚本中发出数据插入/更新,并让 SSDT 在所有操作完成后启用 FK 约束。

如果您对此不太放心,可以按照以下顺序执行:

  • 创建表格
  • 在发布后脚本中填充表格
  • 拍摄该架构
  • -----------------
  • 添加列(带有默认值)和 FK 约束
  • 拍摄该架构
  • -----------------
  • 发布快照 A
  • 发布快照 B

如果您的选项正确设置以在其他所有操作完成后启用检查约束条件,则我认为在大多数情况下无需执行第二个过程。


谢谢,我会尝试在Post-Deploy中运行插入/更新操作。虽然这个(旧)线程的结尾指出它不起作用:http://social.msdn.microsoft.com/Forums/en-US/ssdt/thread/05e195cb-2005-4dcf-84db-705b22972dc8 - Stafford Williams
如果这种情况不经常发生,我建议生成脚本并进行编辑。但是,我认为您应该能够使用智能默认值(或实际默认值)与未启用FK约束来允许您通过项目设置这些值。该线程似乎指向了多个相互依存的更改。 "新约束的脚本验证"选项应该有所帮助。我刚刚在AW2012上进行了快速检查,并创建了一个NOCHECK FK,然后在发布后脚本之后进行了ALTER CHECK。 - Peter Schott
我曾经遇到过同样的问题,这个解决方案对我有效。如果你调用sqlpackage.exe /action:script .....,那么你可以看到它将要运行的脚本。在VS2013中,它会添加FK "with nocheck",运行后部署脚本,然后修改FK,但是像Peter所说的那样使用"WITH CHECK"。 - Amjid Qureshi

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接