多对多关系中的中间表软删除

35

我该如何在连接两种不同类型实体的中间表上设置软删除?我已经添加了 deleted_at 列,但文档说我需要将其放入模型中:

protected $softDelete = true;
当然,我没有中间表的模型。有任何想法吗?

另一种选择是尝试这个 https://github.com/mlezcano1985/laravel-pivot-soft-deletes - PK.
3个回答

81

您可以对Eager Load进行约束:

public function groups()
    {

        return $this
        ->belongsToMany('Group')
        ->whereNull('group_user.deleted_at') // Table `group_user` has column `deleted_at`
        ->withTimestamps(); // Table `group_user` has columns: `created_at`, `updated_at`

    }

不要使用硬删除来解除关系:

User::find(1)->groups()->detach();

你应该像这样使用软删除:

DB::table('group_user')
    ->where('user_id', $user_id)
    ->where('group_id', $group_id)
    ->update(array('deleted_at' => DB::raw('NOW()')));

@RonaldHulshof 我已经尝试过这种方式了,如何使用 User::find(1)->groups()->detach(); 进行软删除。 - iatboy
我一直在寻找这个答案,终于找到了。 - Logus Graphics
2
如果您想使查询可针对Sqlite数据库进行测试,可以将此更新更改为->update(['deleted_at' => Carbon\Carbon::now()]); - Theo Kouzelis
2
这很好,回答了我的问题。然而,在尝试查找关系中的软删除枢轴时会出现问题。例如,我有一个由user_id和group_id组成的复合索引。如果枢轴被软删除,我无法检查关系当前是否存在,然后将deleted_at字段设置回null。否则,由于已经被索引,枢轴记录创建将失败。 - Brad Bird
1
同意 @BradBird 的观点,仍需要一个等效于 Model::withTrashed()Model::onlyTrashed() 的方法。 - Steen Schütt
显示剩余2条评论

18

您还可以使用Laravel的Eloquent BelongsToMany方法updateExistingPivot

$model->relation->updateExistingPivot($relatedId, ['deleted_at' => Carbon\Carbon::now()]);

所以按照 @RonaldHulshof 的例子,您有一个用户模型和一个组关系,这是一种 belongsToMany 关系。

public function groups() {
    return $this->belongsToMany(Group::class)->whereNull('groups_users.deleted_at')->withTimestamps();
}

为了软删除关联表的条目,您可以执行以下操作。

$user->groups()->updateExistingPivot($groupId, ['deleted_at' => Carbon\Carbon::now()]);

3
你可以使用 wherePivot('deleted_at', null) 替代 whereNull('groups_users.deleted_at'),两者的作用是相同的。 - ibnɘꟻ

2
据我了解,中间表只是一段字符串,将一个表的记录与另一个表的记录连接起来,因此不需要软删除方法。
举个例子,假设您有一个用户表和一个组表,每个用户可以拥有多个组,每个组也可以属于多个用户。您的中间表可能是“User_Group”或类似的名称,它只包含两列“user_id”和“group_id”。
您的“User”表和“Group”表应该有一个“deleted_at”列用于软删除,因此当您“删除”一个组时,该组关联将不会出现在“$User->Groups()”中,而中间表行仍然保持不变。如果您恢复了已删除的组,则该组将再次出现在“$User->Groups()”中。
只有在硬删除组记录时,中间表行才应受到影响,在这种情况下,中间表行也应该被硬删除。
现在我已经解释了为什么我认为您不需要向中间表添加软删除;是否仍然有需要这种行为的原因呢?

4
我需要知道用户与一个群组有关联,这就是为什么我需要软删除 - 这个连接仍然保留在数据库中,尽管它不活跃。明白吗? - misaizdaleka
啊,是的,在这种情况下,你可以在你的数据透视表中添加一行额外的列,比如deleted_at,然后按照R. Hulshof的回答进行操作 :) - carbontwelve
这个规则有一个罕见的例外:如果您希望保留关系添加和删除的历史记录,那么拥有软删除选项是有用的。 - Matthew Spence

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接