
在 Laravel 中,使用 $model->relation()->delete() 直接执行 SQL 批量删除,会绕过 Eloquent 生命周期,导致模型 Observer 的 deleted 等事件不被触发;需改用逐个加载并调用 delete() 方法,确保 Observer 正常执行。
在 laravel 中,使用 `$model->relation()->delete()` 直接执行 sql 批量删除,会绕过 eloquent 生命周期,导致模型 observer 的 `deleted` 等事件不被触发;需改用逐个加载并调用 `delete()` 方法,确保 observer 正常执行。
当你在 Payment 模型中调用 $payment->users()->delete() 时,Eloquent 实际执行的是原生 SQL 的 DELETE FROM ... WHERE ... 语句——该操作完全跳过了模型实例化、事件分发和 Observer 回调流程,因此 PaymentUserObserver 中定义的 deleted() 方法根本不会被执行。
✅ 正确做法是:先获取关联的模型集合,再对每个模型实例调用 delete(),从而触发完整的 Eloquent 删除生命周期(包括 deleting、deleted 事件及对应 Observer 方法):
// ✅ 正确:触发 PaymentUserObserver::deleted()
$payment->users()->get()->each->delete();
// 或更清晰的写法(推荐,便于添加日志/异常处理)
$payment->users()->get()->each(function (PaymentUser $user) {
$user->delete(); // 触发 deleted() observer
});⚠️ 注意事项:
-
->get()->each->delete()会为每个关联模型发起一次数据库查询(N+1 风险),若数据量较大(如数百条),建议结合事务与批量优化,或在 Observer 中实现轻量逻辑; - 确保已正确注册 Observer:在
AppServiceProvider::boot()中调用PaymentUser::observe(PaymentUserObserver::class); - 若使用软删除(
SoftDeletes),请确认 Observer 监听的是deleted(硬删)还是forceDeleted(强制软删后),并检查是否误用了->forceDelete(); -
->detach()同样绕过 Observer(仅操作中间表),如需监听解绑行为,应改用->sync([])+ 显式delete(),或在业务层手动触发事件。
? 总结:Eloquent Observer 仅对「模型实例的生命周期方法」生效(如 ->delete()、->save())。任何直接基于 Query Builder 的操作(如 ->delete()、->update() 在关系上调用)均不触发 Observer。务必区分「查询构造器删除」与「模型实例删除」,这是保障业务逻辑(如清理缓存、同步日志、发送通知)可靠执行的关键。


















