【问题标题】:INSTEAD OF Triggers and CASCADE pathsINSTEAD OF 触发器和 CASCADE 路径
【发布时间】:2012-04-30 18:19:25
【问题描述】:

假设我在一个层次结构中有 3 个表:

TableA -> TableB -> TableC

TableCTableB有外键关系,TableBTableA有外键关系。

如果我删除TableA 中的一条记录,它应该通过层次结构向下级联删除。使用ON DELETE CASCADE 可以正常工作。

但是,假设我需要在TableC 上放置一个INSTEAD OF 触发器。我的理解是不能将INSTEAD OF 触发器放在具有删除级联的表上。取自 MSDN:

对于 INSTEAD OF 触发器,在具有指定级联操作 ON DELETE 的引用关系的表上不允许使用 DELETE 选项。

如果我必须从TableB->TableC 中删除级联删除,我需要使用INSTEAD OF 触发器来强制执行参照完整性,然后TableB->TableA 也会出现同样的问题。这是一个简单的例子,但想象级联路径要大得多。它似乎很容易在一条长长的级联路径中滚雪球。

那么处理这种情况的最佳做法是什么?

【问题讨论】:

  • 您希望触发器做什么(而不是删除)不会破坏参照完整性?
  • 我想避免给示例增加进一步的复杂性,因为我不是在寻找表重新设计解决方案,而是针对特定场景的答案。但是作为参考,TableC 使用邻接列表模型来存储层次结构。我正在使用 INSTEAD OF 触发器通过层次结构递归删除。由于使用的是 SS2005,因此无法使用 HierarchyID。
  • 无需重新设计表格,或许这会有所帮助:SQL Server: deleting with self-referential FOREIGN KEY
  • 就我个人而言,我会使用存储过程来控制 DELETE。没有级联,没有触发器。
  • 触发器就像一个乒乓球被扔进一个装满捕鼠器的房间,m'kay

标签: sql sql-server triggers cascade referential-integrity


【解决方案1】:

假设您必须使用 INSTEAD OF 触发器,并且 AFTER 触发器不是一个选项,最好的方法是 a) 严格控制架构,以便您可以 b) 以常规方式编写 INSTEAD OF 触发器以实现 CASCADE DELETE 以及您需要的任何其他操作。

像以前一样创建 FK 约束,但没有任何级联行为。在 FK 名称中,使用一些约定来指示应该发生什么样的级联行为和自定义行为,例如:

  • FK_UC_DC_Table1_Table2 -- 更新级联,删除级联
  • FK_UC_DN_Table1_Table3 -- 更新级联,删除集空

使用任何有意义的东西,但一定要创建 FK,它们是代码生成的有用元数据,您可以使用 FK 名称来记录代码生成器的指令。

然后我会更进一步,将这些表隔离在它们自己的架构中。它们的行为方式与其他表不同,并且在您测试和微调代码生成时,它们一开始会出现更多错误。最好将所有这些隔离起来,并通过一个通用容器轻松识别。

专用架构还将通知修改数据的任何人应用不同的规则和行为。

【讨论】:

    【解决方案2】:

    标准的最佳实践是在视图上定义INSTEAD OF触发器,而不是在上。

    如果您必须在 FK 更新/删除上使用触发器,您最好使用 AFTER,因为它将始终执行。

    如果您想取消级联动作但保留 FK,只需将 FK 动作设置为 NO ACTION。

    【讨论】:

    • 不幸的是,AFTER 触发器在这种情况下不是解决方案,因为在触发触发器之前将违反参照完整性。
    • 您能否更具体地说明您希望触发器做什么
    • 请看问题下的第二条评论。但是,我不太关心实现,而是在一般情况下人们会做什么。我很欣赏这可能取决于实施,但仍然!
    • 我看到了,但是,我认为这不合理。你应该告诉人们你想做什么。我的回答是最佳实践,但你说不可能这样做,你应该说为什么会这样。事实上,你可能有一个糟糕的设计,你将不得不处理它。在某些时候,但这不是我问的原因。我只想知道触发器应该做什么。
    • 我的评论指出该表使用邻接列表模型存储层次结构,因此它使用 INSTEAD OF 触发器来维护 RI。即,如果我删除一个父级,我想级联删除该父级的子级。 AFTER 触发器是不可能的,因为在执行触发器之前删除 RI 将被违反。
    猜你喜欢
    • 2011-09-21
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2012-02-20
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多