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

Laravel软删除关联模型时如何触发事件且统一deleted_at时间戳

方案1:统一时间戳+逐条删除(适用于中等数据量)

核心是提前生成全局统一的删除时间,逐行删除时强制复用该时间戳,同时触发模型事件,配合chunk分批处理避免内存溢出:

A::deleted(function (A $a) {
    $deleteAt = \Carbon\Carbon::now();
    // 处理B模型关联,其他C、D模型逻辑同理
    $a->b()->chunkById(200, function ($bItems) use ($deleteAt) {
        foreach ($bItems as $item) {
            // 手动指定删除时间,保证所有关联模型时间完全一致
            $item->setAttribute($item::DELETED_AT, $deleteAt);
            $item->save();
            // 手动触发删除事件
            $item->fireModelEvent('deleted', false);
        }
    });
});

方案2:封装Trait满足开闭原则

把级联软删除逻辑封装为独立Trait,新增关联模型时无需修改核心事件代码,只需在模型属性中追加关联名即可:

第一步:创建级联软删除Trait

<?php

namespace App\Models\Traits;

use Carbon\Carbon;

trait CascadesSoftDeletes
{
    public static function bootCascadesSoftDeletes()
    {
        static::deleted(function ($model) {
            $deleteAt = Carbon::now();
            // 遍历配置的级联关联列表
            foreach ($model->cascadeSoftDeletes ?? [] as $relationName) {
                $model->$relationName()->chunkById(200, function ($items) use ($deleteAt) {
                    foreach ($items as $item) {
                        $item->setAttribute($item::DELETED_AT, $deleteAt);
                        $item->save();
                        $item->fireModelEvent('deleted', false);
                    }
                });
            }
        });
    }
}

第二步:在主模型中引入使用

use Illuminate\Database\Eloquent\Model;
use Illuminate\Database\Eloquent\SoftDeletes;
use App\Models\Traits\CascadesSoftDeletes;

class A extends Model
{
    use SoftDeletes, CascadesSoftDeletes;
    
    // 新增关联时仅需在此处追加关联方法名,无需修改其他代码
    protected $cascadeSoftDeletes = ['b', 'c', 'd'];

    // 关联定义
    public function b()
    {
        return $this->hasMany(B::class);
    }

    public function c()
    {
        return $this->hasMany(C::class);
    }
}

方案3:批量更新+事件触发(适用于大数据量场景)

如果单条A的关联数据超过万条,逐行处理效率过低,可以先批量更新保证时间一致,再单独触发删除事件兼顾业务逻辑:

A::deleted(function (A $a) {
    $deleteAt = \Carbon\Carbon::now();
    // 批量更新删除时间,仅1次SQL操作,效率极高
    B::where('a_id', $a->id)->update([B::DELETED_AT => $deleteAt]);
    // 查询本次更新的ID列表,仅触发事件无需修改数据
    B::where('a_id', $a->id)
        ->withTrashed()
        ->where(B::DELETED_AT, $deleteAt)
        ->pluck('id')
        ->each(fn ($id) => B::withTrashed()->find($id)?->fireModelEvent('deleted', false));
});

如果删除事件逻辑较重,可将事件触发改为异步队列处理,进一步降低主请求响应耗时。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.10.12 07:57:04