编写通过外键

时间:2016-11-03 20:18:41

标签: sql-server sql-server-data-tools data-migration

我在使用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默认不这样做(也就是说,我也不应该这样做的原因?)

谢谢你们

2 个答案:

答案 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脚本:

  • 首先运行部署前脚本,
  • 第二步 - 使用已编译的* .dacpac运行SqlPackage.exe。

如果您需要在Visual Studio中自动执行该过程......这是一个挑战。没有&#39; BeforePublish&#39; MsBuild Task(如果我错了,请纠正我)。因此,我们无法在数据库发布之前执行部署前脚本,右键单击* .publish.xml配置文件并选择&#34;发布...&#34;

但我们可以捕获AfterBuild任务并执行执行上述两个步骤的PowerShell脚本。

<Target Name="AfterBuild">
    ... Run PowerShell script here
</Target>

因此,每次构建数据库时都会执行数据库发布,但使用部署前脚本时肯定会执行。如果它很烦人,请从Configuration Manager中的解决方案构建中关闭数据库,并单独构建数据库项目。