尝试使用删除级联和softDeletes的外键而没有太多运气。
我有2个表:用户,事件。两个表都有softDeletes。
用户可以拥有0..n个活动 事件有一个user_id,用作用户的外键,如下所示:
$table->foreign('user_id')->references('id')->on('users')->onDelete('CASCADE')->onUpdate('CASCADE');
问题是,当我删除用户时,它会被软删除,但其事件不会 - 软删除或物理删除。
我做错了什么,或者这是正确的Eloquent行为?
其次,如果这是正确的行为,如何最好地实现删除级联?可能会像我这样覆盖我的模型中的delete()方法......
public function delete()
{
//delete all events...
__parent::delete()
}
答案 0 :(得分:11)
DB的外键不会执行任何操作,因为您尚未更改有问题的主键。仅当您更新或删除主键时,才会修改相关行。
从我能找到的有关此主题的所有内容中,解决方案是使用Eloquent的Model Events来侦听删除事件,并更新相关表。
Here's one StackOverflow question about it.
或者,您可以“扩展”delete()
方法并直接包含该功能。 Here's an example.
答案 1 :(得分:2)
要么在删除用户之前删除事件:
$user->events()->delete();
$user->delete();
或者在用户模型中创建客户删除功能:
public function customDelete(){
$this->events()->delete();
return $this->delete();
}
您还可以添加模型观察者并观察删除或删除事件,但在上面提到的场景中,前两种方法将是一种更简单的解决方案。
答案 2 :(得分:0)
如果我理解正确,你试图在两个表中级联softdeletes?
我认为使用ON UPDATE CASCADE执行此操作不是正确的方法。我会试着解释一下原因......
要尝试执行此操作,您需要创建外键与复合键的关系。
即你需要将(events.user_id和deleted_at)链接到(user.id和delete_at)。你改变一个,它会更新另一个。
首先,您需要在deleted_at列中添加默认规则,因为您无法链接空值。
所以添加到两个表的迁移中......
$table->softDeletes()->default('0000-00-00 00:00:00');
使用“id”和“deleted_at”
将唯一键添加到用户表中 Schema::table('users; function($table) {
$table->unique(array('id','deleted_at'))
});
然后在events表中创建一个如此的外键(链接到唯一键)
Schema::table('events; function($table) {
$table->foreign(array('user_id','deleted_at'),'events_deleted_at_foreign_key')->
}->references(array('id','deleted_at'))->on('users')->onUpdate('CASCADE'));
运行此功能,您现在应该发现如果您软删除您的用户,它将软删除其'事件。
但是,如果您现在尝试软删除事件,则外键约束将失败。你为什么要问!?
您正在做的是使用两个表中的id,deleted_at创建父子关系。更新父级,将更新子级。这种关系是不间断的。但是,如果更新子项,则关系现在已断开,将子项保留为表中的孤儿。这使外键约束失败。
Sooo一个冗长的回答,但希望能够很好地解释为什么你要做的事情不会起作用,并且为了节省大量的时间来尝试使用ON UPDATE CASCADE。要么进入TRIGGERS,要么触发TRIGGER来处理你想要做的事情,或者在你的应用程序中处理它。就个人而言,我会使用TRIGGERS这样做,因此数据库仍然是它自己的实体,而不必依赖任何东西来保持数据的完整性。
delimiter //
在每个行的db.users上更新后创建TRIGGER soft_delete_child 开始 如果NEW.deleted_at<> OLD.deleted_at然后 UPDATE事件SET deleted_at = NEW.deleted_at WHERE events.user_id = NEW.id; 万一; END;
// 分隔符;