laravel 如何在 Laravel4 中级联软删除?
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/17977749/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
How to cascade on softdeletes in Laravel4?
提问by RedSash
Tried to use foreign keys with delete cascade and softDeletes without much luck.
尝试将外键与删除级联和 softDeletes 一起使用,但运气不佳。
I have 2 tables: Users, Events. Both tables have softDeletes.
我有 2 个表:用户、事件。两个表都有 softDeletes。
Users can have 0..n Events.
Events have an user_id, used as foreign key on users, like this:
用户可以有 0..n 个事件。
事件有一个 user_id,用作用户的外键,如下所示:
$table->foreign('user_id')->references('id')->on('users')->onDelete('CASCADE')->onUpdate('CASCADE');
Problem is, when I delete an User, it gets soft-deleted, but its Events do not - either soft deletion or physical deletion.
问题是,当我删除一个用户时,它会被软删除,但它的事件不会 - 无论是软删除还是物理删除。
Am I doing something wrong, or is this the correct Eloquent behavior?
我做错了什么,或者这是正确的雄辩行为?
Secondly, if that is the correct behavior, how to best implement deletion cascade? maybe overriding the delete() method in my Models like this ...
其次,如果这是正确的行为,如何最好地实现删除级联?也许像这样覆盖我模型中的 delete() 方法......
public function delete()
{
//delete all events...
__parent::delete()
}
?
?
采纳答案by Aken Roberts
The DB's foreign key won't do anything because you haven't changed the primary key in question. Only if you update or delete the primary key will the related rows be modified.
数据库的外键不会做任何事情,因为您没有更改有问题的主键。只有更新或删除主键,相关行才会被修改。
From everything I can find about this topic, the solution is to use Eloquent's Model Eventsto listen for a delete event, and update the related tables.
从我能找到的关于这个主题的所有内容来看,解决方案是使用 Eloquent 的模型事件来监听删除事件,并更新相关表。
Here's one StackOverflow question about it.
Alternatively, you can "extend" the delete()
method and include the functionality directly as well. Here's an example.
或者,您可以“扩展”该delete()
方法并直接包含该功能。这是一个例子。
回答by Jeremy Gehrs
You're overthinking this.
你想多了。
Either just delete the events right before you delete the users:
要么在删除用户之前删除事件:
$user->events()->delete();
$user->delete();
Or create a customer delete function in the user model:
或者在用户模型中创建一个客户删除函数:
public function customDelete(){
$this->events()->delete();
return $this->delete();
}
You could also add a model observer and watch for the deleting or delete event, but in the scenario you mentioned above, the previous two methods would be a more simple solution.
您也可以添加模型观察者并监视删除或删除事件,但是在您上面提到的场景中,前两种方法将是一个更简单的解决方案。
回答by Marc Hussey
If I understand correctly, you are trying to cascade softdeletes in both tables?
如果我理解正确,您是否正在尝试在两个表中级联软删除?
I believe to do this with ON UPDATE CASCADE is not the correct approach. I'll try to explain why...
我相信用 ON UPDATE CASCADE 做到这一点不是正确的方法。我会试着解释为什么...
To even attempt to do this you need to create a relationship of foreign key to composite key.
为了尝试这样做,您需要创建外键与组合键的关系。
ie you need to link the (events.user_id and deleted_at) to (user.id and delete_at). You change one, it'll update the other.
即您需要将(events.user_id 和deleted_at)链接到(user.id 和delete_at)。你改变一个,它会更新另一个。
First you will need to add a default rule to your deleted_at columns, as you can not link on null values.
首先,您需要向deleted_at 列添加默认规则,因为您无法链接空值。
So add to your migrations for both tables...
$table->softDeletes()->default('0000-00-00 00:00:00');
因此,添加到您对两个表的迁移...
$table->softDeletes()->default('0000-00-00 00:00:00');
Add to your user table a unique key using 'id' and 'deleted_at'
使用“id”和“deleted_at”将唯一键添加到您的用户表
Schema::table('users; function($table) {
$table->unique(array('id','deleted_at'))
});
Schema::table('users; function($table) {
$table->unique(array('id','deleted_at'))
});
Then in the events table create a foreign key like so (links to the unique key)
然后在事件表中创建一个像这样的外键(链接到唯一键)
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'));
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'));
Run this, you should now find if you soft delete your user, it will soft delete its' events.
运行这个,你现在应该发现如果你软删除你的用户,它会软删除它的事件。
However if you now try to soft delete an event, it will fail on the foreign key restraint. Why you might ask!?
但是,如果您现在尝试软删除一个事件,它将在外键限制上失败。为什么你会问!?
Well what you're doing is creating a Parent Child relationship using id,deleted_at in both tables. Updating the parent, will update the child. And the relationship is unbroken. However if you Update the child, the relationship is now broken, leaving the child as an orphan in the table. This fails the foreign key restraint.
那么你正在做的是在两个表中使用 id,deleted_at 创建父子关系。更新父级,将更新子级。而且这种关系是不间断的。但是,如果您更新孩子,则关系现在会中断,将孩子作为表中的孤儿。这不符合外键限制。
Sooo a long winded answer, but hopefully a good explanation of why what you're trying to do won't work and save you a whole lot of time trying to do this with ON UPDATE CASCADE. Either get in to the TRIGGERS, and TRIGGER a function to handle what you're trying to do, or handle it in your application. Personally I'd do it with TRIGGERS so the database remains it's own entity and not having to rely on anything to keep data integrity.
Sooo 一个冗长的答案,但希望能很好地解释为什么您尝试做的事情不起作用,并为您节省大量时间尝试使用 ON UPDATE CASCADE 执行此操作。要么进入 TRIGGERS,然后触发一个函数来处理你想要做的事情,要么在你的应用程序中处理它。就我个人而言,我会使用 TRIGGERS 来做到这一点,因此数据库仍然是它自己的实体,而不必依赖任何东西来保持数据完整性。
delimiter //
CREATE TRIGGER soft_delete_child AFTER UPDATE ON db.users FOR EACH ROW BEGIN IF NEW.deleted_at <> OLD.deleted_at THEN UPDATE events SET deleted_at=NEW.deleted_at WHERE events.user_id=NEW.id; END IF; END;
CREATE TRIGGER soft_delete_child AFTER UPDATE ON db.users FOR EACH ROW BEGIN IF NEW.deleted_at <> OLD.deleted_at THEN UPDATE events SET deleted_at=NEW.deleted_at WHERE events.user_id=NEW.id; 万一; 结尾;
// delimiter ;
// 分隔符;