You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Laravel中restore()恢复软删除记录时新增重复项的问题求助

修复软删除收藏记录重复创建问题

问题背景

实现用户收藏功能时,Favourite模型启用了软删除机制。控制器逻辑为:先检查是否存在对应user_id、content_model和content_id的记录(包含已软删除条目),若存在已删除记录则调用restore()恢复,但实际操作中每次都会新增重复记录,日志持续显示创建新条目。

相关代码

控制器原代码

public function setUserFavourite(Request $request): \Illuminate\Http\JsonResponse
{
    $user = auth()->user();
    $contentModel = $request->input('contentModel');
    $contentId = $request->input('contentId');

    $existingFavourite = $user->favourites()
        ->byContentAlias($contentModel)
        ->where('content_id', $contentId)
        ->first();

    if ($existingFavourite) {
        if ($existingFavourite->trashed()) {
            $existingFavourite->restore();
            \Log::info('Favourite restored:', ['favourite_id' => $existingFavourite->id]);
            return $this->success(new FavouriteResource($existingFavourite), 'Content added to favourites');
        }

        return $this->generalError('This Content is already a favourite');
    }
    $favourite = new Favourite(['user_id' => $user->id]);

    switch ($contentModel){
        case 'Venue':
            $venue = Venue::find($contentId);
            $favourite->favourable()->associate($venue);
            break;

        case 'Organiser':
            $organiser = Organiser::find($contentId);
            $favourite->favourable()->associate($organiser);
            break;

        case 'Event':
            $event = Event::find($contentId);
            $favourite->favourable()->associate($event);
            break;

        default:
            return $this->generalError('Invalid Content Model');
    }
    $favourite->save();
    \Log::info('Favourite created:', ['favourite_id' => $favourite->id]);
    return $this->success(new FavouriteResource($favourite),'Content added to favourites');
}

Favourite模型原代码

<?php

namespace App\Models;

use Illuminate\Database\Eloquent\Factories\HasFactory;
use Illuminate\Database\Eloquent\Model;
use Illuminate\Database\Eloquent\Relations\MorphTo;
use Illuminate\Database\Eloquent\SoftDeletes;

class Favourite extends Model
{
    use HasFactory;
    use SoftDeletes;

    protected $table = 'favourites';

    protected $fillable = [
        'user_id','content_model','content_id'
    ];

    public function favourable(): MorphTo
    {
        return $this->morphTo(__FUNCTION__,'content_model','content_id');
    }

    public function scopeByContentAlias($query, $contentAlias)
    {
        $contentModelNamespace = "App\Models\\" . ucfirst($contentAlias);
        return $query->where('content_model', $contentModelNamespace);
    }
}

User模型原代码

class User extends Authenticatable implements MustVerifyEmail
{
    use HasRoles ,HasApiTokens, HasFactory, Notifiable;

   public function favourites(): HasMany
    {
        return $this->hasMany(Favourite::class,'user_id');
    }
}

问题原因

Laravel的hasMany关联默认会自动过滤deleted_at不为null的软删除记录,导致$user->favourites()查询无法找到已软删除的收藏条目,每次都进入创建新记录的分支。

解决方案

1. 修改查询逻辑,包含软删除记录

在查询已存在的收藏时,添加withTrashed()方法,让查询包含软删除的条目:

$existingFavourite = $user->favourites()
    ->withTrashed() // 新增此行,包含软删除记录
    ->byContentAlias($contentModel)
    ->where('content_id', $contentId)
    ->first();

2. 可选:优化关联定义(按需选择)

如果需要频繁在用户收藏关联中包含软删除记录,可以修改User模型的关联方法,默认包含软删除:

public function favourites(): HasMany
{
    return $this->hasMany(Favourite::class,'user_id')->withTrashed();
}

注意:此修改会让所有$user->favourites查询都包含软删除记录,若有其他场景不需要,建议还是在单独查询时添加withTrashed()更灵活。

3. 验证修复效果

修改后,再次操作已软删除的收藏内容时,系统会找到对应记录并执行restore(),日志会输出恢复的记录ID而非创建新ID,数据库中不会再出现重复条目。

额外优化建议

  • 数据库层面添加唯一索引,防止user_id、content_model、content_id组合重复,即使代码逻辑出错也能从底层避免重复:
    ALTER TABLE favourites ADD UNIQUE INDEX user_content_unique (user_id, content_model, content_id);
    
  • 简化模型关联的associate逻辑,避免冗余的switch语句:
    $modelClass = "App\Models\\" . ucfirst($contentModel);
    if (!class_exists($modelClass)) {
        return $this->generalError('Invalid Content Model');
    }
    $model = $modelClass::find($contentId);
    if (!$model) {
        return $this->generalError('Content not found');
    }
    $favourite->favourable()->associate($model);
    

内容的提问来源于stack exchange,提问作者user23398056

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.30 05:13:11