如何在Laravel4中进行软删除层叠?
如何在Laravel4中进行软删除层叠?
尝试使用带有级联删除和软删除的外键,但运气不太好。
我有两个表:Users(用户)和Events(事件)。这两个表都有软删除功能。
用户可以拥有0到n个事件。
事件有一个user_id,作为对用户的外键,如下所示:
$table->foreign('user_id')->references('id')->on('users')->onDelete('CASCADE')->onUpdate('CASCADE');
问题是,当我删除一个用户时,它会被软删除,但它的事件不会被软删除或物理删除。
我是做错了什么吗,还是这是正确的Eloquent行为?
其次,如果这是正确的行为,如何最好地实现级联删除?也许可以像这样覆盖我的模型中的delete()方法...
public function delete() { //删除所有事件... __parent::delete() }
问题的原因是数据库的外键不会自动级联删除,只有在更新或删除主键时,相关的行才会被修改。
根据我找到的关于这个主题的所有信息,解决方法是使用Eloquent的模型事件来监听删除事件,并更新相关的表。
另一种方法是“扩展”delete()
方法,并直接包含相应的功能。
Cryode,我尝试了模型事件,它可以部分地工作。让我解释一下。真实的情况是有3个表:Users、Events和Comments。Events拥有0到n个Comments。按照链接中的说明,我在Users和Events的boot()方法中添加了逻辑。现在:软删除Event,预期:软删除Comments,结果:OK;软删除User,预期:软删除Events,结果:OK;软删除与这些事件相关的Comments,结果:KO。似乎删除在第一个“级别”之外不会传播。
这是我自己实施的解决方案。我首先绘制出所有我的模型之间的关系图,然后在我的模型中编写扩展Eloquent的删除方法,以实现级联删除。最后,由于这是一个容易出错的任务,我编写单元测试来展示级联效果只影响应该影响的部分。
文章整理如下:
Laravel4中如何在软删除时进行级联删除?
问题的原因是数据库的外键不会自动级联删除,只有在更新或删除主键时,相关的行才会被修改。根据我找到的关于这个主题的所有信息,解决方法是使用Eloquent的模型事件来监听删除事件,并更新相关的表。另一种方法是“扩展”delete()
方法,并直接包含相应的功能。
Cryode,我尝试了模型事件,它可以部分地工作。让我解释一下。真实的情况是有3个表:Users、Events和Comments。Events拥有0到n个Comments。按照链接中的说明,我在Users和Events的boot()方法中添加了逻辑。现在:软删除Event,预期:软删除Comments,结果:OK;软删除User,预期:软删除Events,结果:OK;软删除与这些事件相关的Comments,结果:KO。似乎删除在第一个“级别”之外不会传播。
这是我自己实施的解决方案。我首先绘制出所有我的模型之间的关系图,然后在我的模型中编写扩展Eloquent的删除方法,以实现级联删除。最后,由于这是一个容易出错的任务,我编写单元测试来展示级联效果只影响应该影响的部分。
问题的原因是在Laravel4中,当使用软删除(SoftDeletes)功能时,如果一个模型有关联的子模型(例如:用户模型和事件模型),在删除用户模型时,子模型不会自动删除,需要手动处理。
解决方法有以下几种:
1. 在删除用户模型之前,手动删除关联的子模型(事件模型):
$user->events()->delete(); $user->delete();
2. 在用户模型中创建自定义的删除方法:
public function customDelete(){ $this->events()->delete(); return $this->delete(); }
3. 可以使用模型观察器(Model Observers)来监听删除事件,但在上述场景中,前两种方法更为简单。
问题的出现原因:
尝试使用ON UPDATE CASCADE来级联软删除在两个表中是不正确的方法。这是因为需要创建一个外键到复合键的关系。也就是说,需要将(events.user_id和deleted_at)与(user.id和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')); });
然后在事件表中创建一个外键(链接到唯一键):
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在两个表中的父子关系。更新父项将更新子项,并且关系不会中断。然而,如果你更新子项,关系现在就中断了,导致子项在表中成为孤立项。这违反了外键约束。
因此,要么使用TRIGGERS来处理你尝试做的事情,要么在你的应用程序中处理它。个人建议使用TRIGGERS,这样数据库保持独立实体,不需要依赖任何东西来保持数据完整性。