如何在单表继承上强制引用完整性?

时间:2012-07-16 01:33:07

标签: mysql polymorphic-associations single-table-inheritance cascading-deletes referential-integrity

我已经阅读了一些关于Bill Karwin'ssingle table inheritance个答案,并认为这种方法对我正在考虑的设置有好处:

Playlist
--------
id AUTO_INCREMENT
title

TeamPlaylist
------------
id REFERENCES Playlist.id
teamId REFERENCES Team.id

UserPlaylist
------------
id REFERENCES Playlist.id
userId REFERENCES User.id

PlaylistVideo
-------------
id
playlistId REFERENCES Playlist.id
videoId REFERENCES Video.id

所有CASCADE选项都设置为DELETE,这可以在删除Playlist时正常工作,但是,User或{{1}会发生什么情况被删除了吗?

即。如果删除Team,则User中的行将被删除,但UserPlaylistPlaylist中的引用行仍将保留。我考虑将其强制为PlaylistVideo,但无法知道删除请求是否因为TRIGGER AFTER DELETE已删除或Playlist已被删除而发生。

在这种情况下,强制执行诚信的最佳方法是什么?

编辑(提供ERD)

enter image description here

4 个答案:

答案 0 :(得分:11)

您可以做的是在UsersTeam表上实施触发器,每当从以下任何一行删除行时执行这些触发器:

用户表:

DELIMITER $$
CREATE TRIGGER user_playlist_delete 
BEFORE DELETE ON User FOR EACH ROW
BEGIN
    DELETE a FROM Playlist a
    INNER JOIN UserPlaylist b ON a.id = b.id AND b.userId = OLD.id;
END$$
DELIMITER ;

团队表:

DELIMITER $$
CREATE TRIGGER team_playlist_delete 
BEFORE DELETE ON Team FOR EACH ROW
BEGIN
    DELETE a FROM Playlist a
    INNER JOIN TeamPlaylist b ON a.id = b.id AND b.teamId = OLD.id;
END$$
DELIMITER ;

这些触发器将执行的操作是每次从其中一个表中删除记录时,DELETE操作将使用即将成为Playlists的{​​{1}}表自动执行删除(通过内连接)。

我已对此进行了测试,效果很好。

答案 1 :(得分:4)

好的,我在这里看到你想要的......你想要做的就是运行像

这样的查询
DELETE FROM playlist
WHERE       id 
NOT IN      (
    SELECT  id
    FROM    UserPlayList
    UNION
    SELECT  id
    FROM    TeamPlayList
)

从用户或团队中删除任何一行后

答案 2 :(得分:3)

在我看来,问题是你的UserTeam表应该有一个超类型表(例如Party),而不是播放列表表。

正如您所指出的那样,在播放列表中执行“表继承”会在尝试找出删除内容时受到惩罚。将继承移动到用户/团队级别时,所有这些问题都会消失。

您可以看到this answer for more detail about supertyping/subtyping

我很抱歉不提供代码,因为我不清楚MySQL的语法。

基本概念是超类型表允许您实现数据库类型的多态。当您正在使用的表需要链接到一组子类型中的任何一个时,您只需将FK指向超类型,这将自动获得所需的“只有一个这些都是“商业约束”。超类型与每个子类型表具有“一对一或一”关系,并且每个子类型表在其PK中使用与超类型表中的PK相同的值。

在您的数据库中,通过只有一个Playlist表格,其FK为Party (PartyID),您可以轻松地在数据库级别强制执行业务规则而无需触发器。

答案 3 :(得分:1)

Zane Bien的回答非常明显&但是我有一个想法,不使用触发器这样做,因为触发器有很多问题。

您使用的是任何编程语言吗?如果是,那么,

使用一个transaction并制作数据库auto commit false

为播放列表和PlaylistVideo中的引用行编写删除查询。手动,您必须首先使用该引用ID(使用where condition)编写此查询并运行它。

现在为您的主要任务准备另一个查询,即删除用户,UserPlaylist中的行将被自动删除(由于CASCADE DELETE选项)。现在运行您的第二个查询commit

最后进行交易auto commit true

它运作成功,希望它会有所帮助。