如何使用 dacpac 和 SqlPackage.exe 部署临时表

How to deploy temporal tables with dacpac and SqlPackage.exe

我们正尝试在 SQL Server 2016 中使用临时 tables。我们正在 Visual Studio 2017 中的 SSDT 15.1.6 中开发 SQL 脚本,但是我们在尝试部署构建过程中生成的 dacpac 时遇到了问题。

我们的 dacpac 是使用 SqlPackage.exe 部署的,我们在尝试部署 dacpac 时遇到此错误:

Creating [dbo].[TestHISTORY].[ix_TestHISTORY]...
An error occurred while the batch was being executed.
Updating database (Failed)
Could not deploy package.
Error SQL72014: .Net SqlClient Data Provider:

Msg 1913, Level 16, State 1, Line 1
The operation failed because an index or statistics with name 'ix_TestHISTORY' already exists on table 'dbo.TestHistory'.

Error SQL72045: Script execution error. The executed script:
CREATE CLUSTERED INDEX [ix_TestHISTORY] ON [dbo].[TestHistory]([SysStart] ASC, [SysEnd] ASC);

当我们在 SSDT 中创建时间 table 时,我们有以下内容:

CREATE TABLE [dbo].[Test]
(
    [Id] INT NOT NULL PRIMARY KEY,
    [SysStart] DATETIME2 (7) GENERATED ALWAYS AS ROW START NOT NULL,
    [SysEnd] DATETIME2 (7) GENERATED ALWAYS AS ROW END NOT NULL,
    PERIOD FOR SYSTEM_TIME ([SysStart], [SysEnd])
)
WITH (SYSTEM_VERSIONING = ON(HISTORY_TABLE=[dbo].[TestHISTORY], DATA_CONSISTENCY_CHECK=ON))

据我所知,问题出在 dacpac 创建上。项目构建完成后,创建的dacpac如下所示:

CREATE TABLE [dbo].[test]  
(
    [Id]       INT NOT NULL PRIMARY KEY CLUSTERED ([Id] ASC),
    [SysStart] DATETIME2 (7) GENERATED ALWAYS AS ROW START NOT NULL,
    [SysEnd]   DATETIME2 (7) GENERATED ALWAYS AS ROW END   NOT NULL,
    PERIOD FOR SYSTEM_TIME ([SysStart], [SysEnd])
)
WITH (SYSTEM_VERSIONING = ON (HISTORY_TABLE=[dbo].[testHISTORY], DATA_CONSISTENCY_CHECK=ON));
GO

CREATE TABLE [dbo].[testHISTORY] 
(
    [Id]       INT           NOT NULL,
    [SysStart] DATETIME2 (7) NOT NULL,
    [SysEnd]   DATETIME2 (7) NOT NULL
);
GO

CREATE CLUSTERED INDEX [ix_testHISTORY]
    ON [dbo].[testHISTORY]([SysEnd] ASC, [SysStart] ASC);
GO

我怀疑因为我们使用的是 temporal table with a default history table 我们不能让 dacpac 创建那些额外的创建语句。因为这实际上导致 SQL 服务器尝试创建这些项目两次,从而导致上述错误。

有谁知道我们可能遗漏了什么?或者,如果您使用 dacpac 部署临时 tables,那么使用 user-defined history tables 是您唯一的选择吗?

您可以尝试的一种潜在的 hacky 解决方法是 pre-deployment 脚本;

https://msdn.microsoft.com/en-us/library/jj889461(v=vs.103).aspx

它们在 'Generation of deployment script' 和 'Execution of the deployment script' 之间执行。因此,如果您无法避免索引名称发生冲突,您可以在升级前重命名现有索引,这很老套,我假设您是 deploying/updating 实时数据库的模式而不是创建新数据库

顺便说一句,错误消息中的列名 'ValidFrom' & 'ValidTo' 在哪里?如果是自动生成的,那么它应该是 'SysEnd' & 'SysStart'

我们在时态表和 DACPAC 之间遇到了很多问题。一些有用的小贴士:

  • 明确声明历史表 - 这比人们想象的要深入得多。当 adding/removing 列时,您可以在历史表上定义默认值,从而绕过数据已经在表中时出现的许多问题。
  • 为所有内容添加默认值 - 这怎么强调都不为过。默认值是 DACPAC 最好的朋友。
  • 查看脚本 - 很高兴将 DACFx 视为放手,但事实并非如此。偶尔回顾一下脚本,您将获得大量见解(看来您已经是了!)
  • 明确命名您的索引 - DACFx 有时会对 indices/tables/other 内容使用临时名称。一致性为王,对吧?
  • 查看所有发布配置文件选项 - 有时,配置文件中有您没有想到的设置。在我们意识到发布配置文件中有事务脚本设置之前,我们进行了大量手动干预。

还要调查是谁将您的 DACPAC 变成脚本。 VS 使用 SqlPackage.exe,但我有时会从 DACFx DLL 中得到不同的结果。这可能是两者之间不同的配置,但很难找出。两者都试一下,看看哪个效果更好。

祝你好运!希望这对您有所帮助!