如何在Laravel4中级联软件?

时间:2013-07-31 18:08:22

标签: laravel laravel-4 eloquent cascading-deletes

尝试使用删除级联和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()
}

3 个答案:

答案 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();
}

您还可以添加模型观察者并观察删除或删除事件,但在上面提到的场景中,前两种方法将是一种更简单的解决方案。

http://laravel.com/docs/4.2/eloquent#model-observers

答案 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;

// 分隔符;