使用sqlpackage.exe发布dacpac时,它首先运行Schema Compare,然后运行预部署脚本。例如,当您需要删除表或重命名列时,这会导致问题。架构比较是在修改对象和部署失败之前完成的。必须重复发布才能考虑新模式。
任何人都有解决方法,不涉及两次发布?
答案 0 :(得分:8)
Gert Drapers将其称为部署前脚本here
实际上这是一个挑战。如果需要将非可空和外键列添加到充满数据的表中 - 您只能使用单独的脚本。
如果您是唯一的开发人员 - 这不是问题,但是当您拥有一个大型团队时,必须在每次数据库发布之前以某种方式执行“单独脚本”。
我们使用的解决方法:
<UsingTask
TaskName="MSBuild.MsSql.DeployTask"
AssemblyFile="$(MSBuildProjectDirectory)\Deploy\MsBuild.MsSql.DeployTask.dll" />
<Target Name="AfterBuild">
<DeployTask
Configuration="$(Configuration)"
DeployConfigPath="$(MSBuildProjectDirectory)\Deploy\Deploy.config"
ProjectDirectory="$(MSBuildProjectDirectory)"
OutputDirectory="$(OutputPath)"
DacVersion="$(DacVersion)">
</DeployTask>
</Target>
上面的MsBuild.MsSql.DeployTask.dll 是自定义MSBuild任务。
因此可以从Visual Studio调用“Before-publish”脚本。
对于CI,我们使用批处理文件(* .bat),其中调用了相同的两个实用程序(SQLCMD.EXE&amp; SQLPACKAGE.EXE)。
我们得到的最后一个过程有点复杂,应该在另一篇文章中描述 - 这里我只提到了一个方向:)
答案 1 :(得分:1)
从使用visual studio转移到使用驱动sqlpackage.exe的脚本,您可以在比较之前灵活地运行脚本:
https://the.agilesql.club/Blog/Ed-Elliott/Pre-Deploy-Scripts-In-SSDT-When-Are-They-Run
编
答案 2 :(得分:1)
我们遇到了在部署数据库项目期间需要将数据从一个表转换为另一个表的情况。当然,使用数据库项目是一个问题,因为在预部署中目标表(列)仍然不存在,但在部署后脚本中,源表(列)已经不存在。
要将数据从TableA转换为TableB,我们使用了以下想法(此方法可用于任何数据修改):
由于我们将中间数据存储在临时表中,因此我们不需要预部署前脚本。
我想说使用预部署前脚本的方法具有相同的中间(临时)数据,但它不存储在临时表中,而是存储在实际表中。它发生在预部署之前和预部署之间。执行预部署脚本后,此中间数据将消失。
更重要的是,使用临时表的方法使我们能够面对以下复杂但真实的情况:想象一下,我们的数据库项目中有两个转换:
除此之外,我们有两个数据库:
尽管如此,我们可以处理这种情况。我们在预部署中只需要一个新操作。在转换之前,我们尝试将数据从dbo.TableA复制到#TableA。转换脚本仅适用于临时表。
让我向您展示这个想法在DatabaseA和DatabaseB中是如何工作的。 假设DB项目具有两对部署前和后部脚本:&#34; TableA - &gt;表B&#34;和&#34;表B - &gt;表C&#34 ;.
以下是&#34; TableB - &gt;的脚本示例。表C&#34;转化
预部署脚本
----[The data preparation block]---
--We must prepare to possible transformation
--The condition should verufy the existance of necessary columns
IF OBJECT_ID('dbo.TableB') IS NOT NULL AND
OBJECT_ID('tempdb..#TableB') IS NULL
BEGIN
CREATE TABLE #TableB
(
[Id] INT NOT NULL PRIMARY KEY,
[Value1] VARCHAR(50) NULL,
[Value2] VARCHAR(50) NULL
)
INSERT INTO [#TableB]
SELECT [Id], [Value1], [Value2]
FROM dbo.TableB
END
----[The data transformation block]---
--The condition of the transformation start
--It is very important. It must be as strict as posible to ward off wrong executions.
--The condition should verufy the existance of necessary columns
--Note that the condition and the transformation must use the #TableA instead of dbo.TableA
IF OBJECT_ID('tempdb..#TableB') IS NOT NULL
BEGIN
CREATE TABLE [#TableC]
(
[Id] INT NOT NULL PRIMARY KEY,
[Value] VARCHAR(50) NULL
)
--Data transformation. The source and destimation tables must be temporary tables.
INSERT INTO [#TableC]
SELECT [Id], Value1 + ' '+ Value2 as Value
FROM [#TableB]
END
部署后脚本
--Here must be a strict condition to ward of a failure
--Checking of the existance of fields is a good idea
IF OBJECT_ID('dbo.TableC') IS NOT NULL AND
OBJECT_ID('tempdb..#TableC') IS NOT NULL
BEGIN
INSERT INTO [TableC]
SELECT [Id], [Value]
FROM [#TableC]
END
在DatabaseA中,预部署脚本已经创建了#TableA。因此,由于数据库中没有dbo.TableB,数据准备块不会被执行。 但是,将执行数据转换,因为数据库中的#TableA是由&#34; TableA - &gt;的转换块创建的。表B&#34;
在DatabaseB中,&#34; TableA - &gt;的数据准备和转换块。表B&#34;脚本不会被执行。但是我们已经在dbo.TableB中获得了转换后的数据。因此,&#34; TableB - &gt;的数据准备和转换块。表C&#34;将毫无问题地执行。