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
相关产品推荐
相关产品推荐

