我在使用SQL Server数据工具(SSDT)编写可靠的数据迁移时遇到问题。我的架构如下所示:
create table [dbo].[Orders]
(
Id INT identity(1,1) NOT NULL,
OrderDate date NOT NULL,
constraint PK_dbo_Orders primary key clustered (Id)
)
--has a foreign key to Orders, on delete block
create table [dbo].[OrderItems]
(
OrderId int not null,
ItemNumber varchar(20) not null,
Quantity int not null,
constraint PK_OrderItems primary key clustered (OrderId, ItemNumber),
constraint FK_OrderItems_OrderId foreign key (OrderId) references dbo.Orders(Id)
)
我想在Id和OrderDate之间的Orders表中添加一个“OnlineOrder bit not null”列。由于简单的“alter table”不够(不可为空,没有默认值),我必须手动进行迁移。我尝试过的脚本看起来像这样:
预部署:
--if Orders exists
if exists(select 1 from sys.tables where name = 'Orders')
begin
--save the data
select * into _tmp_Orders from Orders
--empty the existing table
delete from Orders
if @@ERROR <> 0
begin
drop table _tmp_Orders
end
end
部署后:
if exists(select 1 from sys.tables where name = 'Orders')
and exists(select 1 from sys.tables where name = '_tmp_Orders')
begin
--fill the orders table back up
insert into Orders(Id, CustomerId, OrderDate, OnlineOrder)
select Id, CustomerId, OrderDate, 0
from _tmp_Orders
if @@ERROR = 0
begin
drop table _tmp_Orders
end
end
这可行,但不幸的是来自OrderItems的外键 - &gt; Order阻止了预部署脚本中的删除,整个事情都爆发了。我认为 SSDT在预部署之前禁用了约束并在部署后重新启用,但这显然只适用于触发器,而不是约束/外键。
问题#1:有没有办法强制SSDT在部署期间禁用数据库中的所有FK(包括我的.dacpac的“未知”)?这将是最简单的。
问题#2:如果没有,我将不得不自己检查这些限制。是否有一个原因SSDT默认不这样做(也就是说,我也不应该这样做的原因?)
谢谢你们
答案 0 :(得分:1)
你可能偶然发现了#34;智能默认&#34;功能是有用的。
鉴于您要添加bit
列,并使用零预先填充,如果您选中&#34;生成智能默认值(如果适用)&#34;在您的发布配置文件中(或将相应的参数提供给sqlpackage.exe
),您将获得预先填充零的列。此功能的工作原理是创建默认值,然后在创建列后立即删除它。
这有帮助吗?
答案 1 :(得分:0)
是的,在某些情况下,不可能仅使用部署前和部署后的脚本来完成任务。
假设你需要:
not null
查找表的外键。我怀疑使用预部署和部署后脚本可以完成此任务,即使使用智能默认设置也是如此。
查找表填写了部署后的脚本,所以外来的 在填充查找表之前创建密钥 - 这是 错误。
由user1935361添加:
以上引用不准确。
外键是 已创建,但已创建WITH NOCHECK。部署后脚本 在创建外键之后运行,但在实际之前运行 检查(刚验证过)。
另一个问题是在架构比较之后执行预部署!因此,发布会捕获模式中的错误,并在部署前脚本执行之前将其抛出。请参阅Gert Drapers的the article。我没有听说过这种行为自2009年以来发生了变化。
因此,解决方法是创建部署前脚本(或Gert Drapers如何将其称为预部署前)并在公共发布过程之前执行它。 / p>
如果要在Visual Studio外部执行此操作,则可以执行PowerShell脚本:
如果您需要在Visual Studio中自动执行该过程......这是一个挑战。没有&#39; BeforePublish&#39; MsBuild Task(如果我错了,请纠正我)。因此,我们无法在数据库发布之前执行部署前脚本,右键单击* .publish.xml配置文件并选择&#34;发布...&#34;
但我们可以捕获AfterBuild
任务并执行执行上述两个步骤的PowerShell脚本。
<Target Name="AfterBuild">
... Run PowerShell script here
</Target>
因此,每次构建数据库时都会执行数据库发布,但使用部署前脚本时肯定会执行。如果它很烦人,请从Configuration Manager中的解决方案构建中关闭数据库,并单独构建数据库项目。