如何删除评论时删除评论的所有后代的评论系统?

时间:2016-01-13 22:27:45

标签: sql sql-server tsql database-design

我正在制作一个完整的堆栈Web应用程序,并且正在尝试尽可能多地在数据库中编写逻辑。

我有一个像

这样的评论系统
    1
   / \
  2   3
 / \
4   5

我代表

   Comments
===============
  id | ...
---------------
   1 | ...
   2 | ...
   3 | ...
   4 | ...
   5 | ...

           CommentTree
===================================
  id | ancestor | descendant | ...
-----------------------------------
  1  |     1    |      1     | ...
  2  |     1    |      2     | ...
  3  |     1    |      3     | ...
  4  |     1    |      4     | ...
  5  |     1    |      5     | ...
  6  |     2    |      2     | ...
  7  |     2    |      4     | ...
  8  |     2    |      5     | ...
  9  |     3    |      3     | ...
  10 |     4    |      4     | ...
  11 |     5    |      5     | ...

我想知道如何进行设置,以便在删除评论时删除所有后代。我知道如何设置它以在删除祖先时删除对祖先 - 后代关系的引用:

 FOREIGN KEY (ancestor) REFERENCES Comments(id) ON DELETE CASCADE

但是如何让 操作触发后续评论也被删除?

换句话说,发生以下事件链

  1. 评论已删除
  2. 祖先等于该评论的ID的树中的所有行都将被删除
  3. 将删除其ID等于在步骤2中删除的后代的所有注释
  4. 我已经完成了第1步和第2步,但我怎么能在那里工作第3步?我是否必须编写一个在删除每个树元素时触发的过程?你能告诉我一个这样看的例子吗?

1 个答案:

答案 0 :(得分:2)

我认为不可能实现使用约束。这是因为会发生循环。您可以尝试使用触发器来实现它,但我不推荐它,因为可见性非常低(我甚至不确定它是否可行)。

我建议您在删除评论时调用的存储过程。它更容易维护,可见性更好。

create procedure DeleteComment(
  @CommentID int
  )
  as 
 declare
  @CommentToDelete TABLE (id int);
  begin

  -- save comments for deletion
  insert into @CommentToDelete 
  select descendant from CommentTree  
  where  ancestor = @CommentID;

  -- delete relation from tree
with tree (commentTreeID, ancestor, descendant , path,  src) as 
(
select id,  ancestor,  descendant , cast ( '-'+ cast(id as varchar(2000)) +'-' as varchar(2000))   , 0from 
CommentTree ct
where ct.ancestor = @CommentID
union all
select CT.Id, CT.ancestor,  CT.descendant ,cast( t.path + '-' + cast(id as varchar(2000)) +'-' as varchar(2000)), 1
from tree t
join CommentTree CT 
 on CT.ancestor = t.descendant and
  CHARINDEX (cast( '-' + cast(id as varchar(2000)) +'-' as varchar(2000)), t.path) = 0 and
  t.src != 2
union all
 select CT.Id, CT.descendant,  CT.ancestor ,cast( t.path + '-' + cast(id as varchar(2000)) +'-' as varchar(2000)), 2
from tree t
join CommentTree CT 
 on CT.descendant = t.descendant and
 CHARINDEX(cast( '-' + cast(id as varchar(2000)) +'-' as varchar(2000)), t.path) =0  and
   t.src != 2
 ) 
 delete CT 
  from CommentTree CT 
  join tree t 
  on t.commentTreeID = CT.ID;

  -- now we can delete comments
  delete Comments
  where id in (select id from  @CommentToDelete);

end;
  • 第一个连接用于在树上向下(src = 1)。
  • 第二个连接用于在树上(src = 2)。

当我们上升时,我们不想再次上升或下跌=> t.src != 2让它成为现实。

  • CHARINDEX (... )保护我们免受循环。