12

尝试将外键与删除级联和软删除一起使用,但运气不佳。

我有 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()
}

?

4

3 回答 3

11

数据库的外键不会做任何事情,因为您没有更改相关的主键。仅当您更新或删除主键时,才会修改相关行。

从我能找到的关于这个主题的所有内容中,解决方案是使用 Eloquent 的模型事件来监听删除事件,并更新相关表。

这是关于它的一个 StackOverflow 问题。

或者,您可以“扩展”该delete()方法并直接包含该功能。这是一个例子。

于 2013-07-31T21:11:14.570 回答
2

你多虑了。

在删除用户之前删除事件:

$user->events()->delete();
$user->delete();

或者在用户模型中创建一个客户删除函数:

public function customDelete(){
    $this->events()->delete();
    return $this->delete();
}

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

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

于 2015-01-22T17:49:50.227 回答
0

如果我理解正确,您是在尝试在两个表中级联软删除吗?

我相信用 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')) });

然后在事件表中创建一个像这样的外键(指向唯一键的链接)

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 来做到这一点,因此数据库仍然是它自己的实体,而不必依赖任何东西来保持数据完整性。

delimiter //

在 db.users 上更新后创建触发器 soft_delete_child,如果 NEW.deleted_at <> OLD.deleted_at 则开始更新事件 SET deleted_at=NEW.deleted_at WHERE events.user_id=NEW.id; 万一; 结尾;

// 分隔符;

于 2015-01-16T14:22:35.557 回答