我们有一个 DACPAC (sqlproj) 解决方案,它有一些表和一个运行一些 DML 查询的部署后脚本。如果 DML 查询失败(我提出了一个严重性 = 20 的错误),我想回滚所有更改 - 包括 dacpac 所做的 DDL 更改和部署后文件更改。当我要升级现有的目标数据库时,这特别有用。
我正在努力在发布 DACPAC 时进行原子数据库升级 - 只有在部署后脚本中的所有内容都成功时,DACPAC 解决方案中提到的所有 DDL 更改才应该发布。
由于 DACPAC DDL 更改在调用部署后脚本之前已提交,因此我认为使用 DacServices.GenerateDeployScript 将所有 DAC 更改生成为单个脚本文件会有所帮助。看起来不那么直截了当。
有没有人尝试过这样的事情(并且失败/通过)?
我面临许多挑战,例如... 创建/更改数据库不应该在事务中。回滚根本没有发生。
[编辑 10Nov]:在此处粘贴 dacpac 生成的部署脚本,以便我可以更好地解释我的问题(希望如此)
/*
Deployment script for 9Nov
This code was generated by a tool.
Changes to this file may cause incorrect behavior and will be lost if
the code is regenerated.
*/
GO
SET ANSI_NULLS, ANSI_PADDING, ANSI_WARNINGS, ARITHABORT, CONCAT_NULL_YIELDS_NULL, QUOTED_IDENTIFIER ON;
SET NUMERIC_ROUNDABORT OFF;
GO
:setvar INSTALL_DIR "D:\EDW_9Nov\"
:setvar DatabaseName "9Nov"
:setvar DefaultFilePrefix "9Nov"
:setvar DefaultDataPath "C:\Program Files\Microsoft SQL Server\MSSQL12.MSSQLSERVER\MSSQL\DATA\"
:setvar DefaultLogPath "C:\Program Files\Microsoft SQL Server\MSSQL12.MSSQLSERVER\MSSQL\DATA\"
GO
:on error exit
GO
/*
Detect SQLCMD mode and disable script execution if SQLCMD mode is not supported.
To re-enable the script after enabling SQLCMD mode, execute the following:
SET NOEXEC OFF;
*/
:setvar __IsSqlCmdEnabled "True"
GO
IF N'$(__IsSqlCmdEnabled)' NOT LIKE N'True'
BEGIN
PRINT N'SQLCMD mode must be enabled to successfully execute this script.';
SET NOEXEC ON;
END
GO
USE [master];
GO
IF (DB_ID(N'$(DatabaseName)') IS NOT NULL)
BEGIN
ALTER DATABASE [$(DatabaseName)]
SET SINGLE_USER WITH ROLLBACK IMMEDIATE;
DROP DATABASE [$(DatabaseName)];
END
GO
PRINT N'Creating $(DatabaseName)...'
GO
CREATE DATABASE [$(DatabaseName)]
ON
PRIMARY(NAME = [$(DatabaseName)], FILENAME = N'$(DefaultDataPath)$(DefaultFilePrefix)_Primary.mdf')
LOG ON (NAME = [$(DatabaseName)_log], FILENAME = N'$(DefaultLogPath)$(DefaultFilePrefix)_Primary.ldf') COLLATE SQL_Latin1_General_CP1_CI_AS
GO
IF EXISTS (SELECT 1
FROM [master].[dbo].[sysdatabases]
WHERE [name] = N'$(DatabaseName)')
BEGIN
ALTER DATABASE [$(DatabaseName)]
SET ANSI_NULLS ON,
ANSI_PADDING ON,
ANSI_WARNINGS ON,
ARITHABORT ON,
CONCAT_NULL_YIELDS_NULL ON,
NUMERIC_ROUNDABORT OFF,
QUOTED_IDENTIFIER ON,
ANSI_NULL_DEFAULT ON,
CURSOR_DEFAULT LOCAL,
RECOVERY SIMPLE,
CURSOR_CLOSE_ON_COMMIT OFF,
AUTO_CREATE_STATISTICS ON,
AUTO_SHRINK OFF,
AUTO_UPDATE_STATISTICS ON,
RECURSIVE_TRIGGERS OFF
WITH ROLLBACK IMMEDIATE;
ALTER DATABASE [$(DatabaseName)]
SET AUTO_CLOSE OFF
WITH ROLLBACK IMMEDIATE;
END
GO
IF EXISTS (SELECT 1
FROM [master].[dbo].[sysdatabases]
WHERE [name] = N'$(DatabaseName)')
BEGIN
ALTER DATABASE [$(DatabaseName)]
SET ALLOW_SNAPSHOT_ISOLATION OFF;
END
GO
IF EXISTS (SELECT 1
FROM [master].[dbo].[sysdatabases]
WHERE [name] = N'$(DatabaseName)')
BEGIN
ALTER DATABASE [$(DatabaseName)]
SET READ_COMMITTED_SNAPSHOT OFF
WITH ROLLBACK IMMEDIATE;
END
GO
IF EXISTS (SELECT 1
FROM [master].[dbo].[sysdatabases]
WHERE [name] = N'$(DatabaseName)')
BEGIN
ALTER DATABASE [$(DatabaseName)]
SET AUTO_UPDATE_STATISTICS_ASYNC OFF,
PAGE_VERIFY NONE,
DATE_CORRELATION_OPTIMIZATION OFF,
DISABLE_BROKER,
PARAMETERIZATION SIMPLE,
SUPPLEMENTAL_LOGGING OFF
WITH ROLLBACK IMMEDIATE;
END
GO
IF IS_SRVROLEMEMBER(N'sysadmin') = 1
BEGIN
IF EXISTS (SELECT 1
FROM [master].[dbo].[sysdatabases]
WHERE [name] = N'$(DatabaseName)')
BEGIN
EXECUTE sp_executesql N'ALTER DATABASE [$(DatabaseName)]
SET TRUSTWORTHY OFF,
DB_CHAINING OFF
WITH ROLLBACK IMMEDIATE';
END
END
ELSE
BEGIN
PRINT N'The database settings cannot be modified. You must be a SysAdmin to apply these settings.';
END
GO
IF IS_SRVROLEMEMBER(N'sysadmin') = 1
BEGIN
IF EXISTS (SELECT 1
FROM [master].[dbo].[sysdatabases]
WHERE [name] = N'$(DatabaseName)')
BEGIN
EXECUTE sp_executesql N'ALTER DATABASE [$(DatabaseName)]
SET HONOR_BROKER_PRIORITY OFF
WITH ROLLBACK IMMEDIATE';
END
END
ELSE
BEGIN
PRINT N'The database settings cannot be modified. You must be a SysAdmin to apply these settings.';
END
GO
ALTER DATABASE [$(DatabaseName)]
SET TARGET_RECOVERY_TIME = 0 SECONDS
WITH ROLLBACK IMMEDIATE;
GO
IF EXISTS (SELECT 1
FROM [master].[dbo].[sysdatabases]
WHERE [name] = N'$(DatabaseName)')
BEGIN
ALTER DATABASE [$(DatabaseName)]
SET FILESTREAM(NON_TRANSACTED_ACCESS = OFF),
CONTAINMENT = NONE
WITH ROLLBACK IMMEDIATE;
END
GO
IF EXISTS (SELECT 1
FROM [master].[dbo].[sysdatabases]
WHERE [name] = N'$(DatabaseName)')
BEGIN
ALTER DATABASE [$(DatabaseName)]
SET AUTO_CREATE_STATISTICS ON(INCREMENTAL = OFF),
MEMORY_OPTIMIZED_ELEVATE_TO_SNAPSHOT = OFF,
DELAYED_DURABILITY = DISABLED
WITH ROLLBACK IMMEDIATE;
END
GO
USE [$(DatabaseName)];
GO
IF fulltextserviceproperty(N'IsFulltextInstalled') = 1
EXECUTE sp_fulltext_database 'enable';
GO
PRINT N'Creating [EDW_INTERNAL]...';
GO
CREATE SCHEMA [EDW_INTERNAL]
AUTHORIZATION [dbo];
GO
PRINT N'Creating [EDW_INTERNAL].[DB_VERSIONS]...';
GO
CREATE TABLE [EDW_INTERNAL].[DB_VERSIONS] (
[ID] BIGINT IDENTITY (1, 1) NOT NULL,
[MODULE] VARCHAR (30) NOT NULL,
[FROM_VERSION] VARCHAR (20) NOT NULL,
[TO_VERSION] VARCHAR (20) NOT NULL,
[UPGRADE_DML_APPLIED_YN] VARCHAR (1) NOT NULL,
CONSTRAINT [PK_DB_VERSIONS] PRIMARY KEY CLUSTERED ([MODULE] ASC, [FROM_VERSION] ASC, [TO_VERSION] ASC)
);
GO
PRINT N'Creating [EDW_INTERNAL].[DML_UPGR_SCRIPT_MASTER]...';
GO
CREATE TABLE [EDW_INTERNAL].[DML_UPGR_SCRIPT_MASTER] (
[MODULE] VARCHAR (30) NOT NULL,
[FROM_VERSION] VARCHAR (20) NOT NULL,
[TO_VERSION] VARCHAR (20) NOT NULL,
[APPLY_ORDER] INT NOT NULL,
[UPGR_SCRIPT_FILEPATH] VARCHAR (1024) NOT NULL,
CONSTRAINT [PK_DML_UPGR_SCRIPT_MASTER] PRIMARY KEY CLUSTERED ([APPLY_ORDER] ASC, [TO_VERSION] ASC, [FROM_VERSION] ASC, [MODULE] ASC)
);
GO
PRINT N'Creating unnamed constraint on [EDW_INTERNAL].[DB_VERSIONS]...';
GO
ALTER TABLE [EDW_INTERNAL].[DB_VERSIONS]
ADD DEFAULT 'N' FOR [UPGRADE_DML_APPLIED_YN];
GO
PRINT N'Creating [EDW_INTERNAL].[UPGRADE_DML]...';
GO
CREATE PROCEDURE EDW_INTERNAL.UPGRADE_DML
@Module VARCHAR(30)
AS
BEGIN
DECLARE @Failure bit = 1;
IF @Failure = 1
BEGIN
RAISERROR
(N'One or more database upgrade query statements have failed. Please check the DML Upgrade Log table for details.',
20, -- Severity.
1 -- State
) WITH LOG;
END
END
GO
/*
Post-Deployment Script Template
--------------------------------------------------------------------------------------
This file contains SQL statements that will be appended to the build script.
Use SQLCMD syntax to include a file in the post-deployment script.
Example: :r .\myfile.sql
Use SQLCMD syntax to reference a variable in the post-deployment script.
Example: :setvar TableName MyTable
SELECT * FROM [$(TableName)]
--------------------------------------------------------------------------------------
*/
-- Reference to load the Version Upgrade tables with rows
--:r VersionUpgradeRowsPopulate.sql
-- execute
EXEC [EDW_INTERNAL].[UPGRADE_DML] @MODULE = 'Test_Common'
GO
GO
DECLARE @VarDecimalSupported AS BIT;
SELECT @VarDecimalSupported = 0;
IF ((ServerProperty(N'EngineEdition') = 3)
AND (((@@microsoftversion / power(2, 24) = 9)
AND (@@microsoftversion & 0xffff >= 3024))
OR ((@@microsoftversion / power(2, 24) = 10)
AND (@@microsoftversion & 0xffff >= 1600))))
SELECT @VarDecimalSupported = 1;
IF (@VarDecimalSupported > 0)
BEGIN
EXECUTE sp_db_vardecimal_storage_format N'$(DatabaseName)', 'ON';
END
GO
PRINT N'Update complete.';
GO