Laravel怎么实现软删除_Laravel数据回收站功能配置【指南】

3次阅读

laravel软删除强制使用deleted_at字段,不可配置;模型必须显式use SoftDeletes;restore()不触发模型事件;查询需用withTrashed()等方法显式控制软删除状态。

Laravel怎么实现软删除_Laravel数据回收站功能配置【指南】

软删除字段名必须叫 deleted_at

Laravel 的软删除机制硬编码依赖 deleted_at 字段,不是配置项,不能改。如果你的表用的是 is_deleteddeleted_timeSoftDeletes trait 会完全失效——查不到、恢复不了、连 withTrashed() 都没反应。

实操建议:

  • 新建迁移时固定用 $table->softDeletes();,它会自动建 deleted_at(类型为 timestamp NULL
  • 已有表需重命名字段:先加 deleted_at,再把旧字段值转过去(注意 NULL 处理),最后删旧字段
  • 别试图通过重写 getDeletedAtColumn() 方法绕过——Laravel 8+ 已移除该方法,强行定义会被忽略

use SoftDeletes 必须加在模型里,且不能只加在父类

软删除不是全局开关,是模型级行为。即使你有 BaseModel 继承Model,也必须在每个具体模型中显式 use SoftDeletes;,否则 delete() 仍执行物理删除。

常见错误现象:

  • 调用 User::find(1)->delete() 后数据真的没了,日志里也没触发 deleting 事件
  • User::withTrashed()->get() 返回空集合,但数据库deleted_at 明明有值

原因:模型没 use trait,Laravel 把它当普通模型处理,deleted_at 字段只是个普通字段,不参与任何逻辑。

restore() 不会触发 savingupdating 事件

这是 Laravel 软删除的设计事实,不是 bug。调用 $user->restore() 时,底层走的是 update(['deleted_at' => null]),跳过了模型的常规保存生命周期。

所以如果你依赖 saving 事件来自动更新 updated_at 或同步缓存,restore() 后这些逻辑不会执行。

解决方案:

  • 手动补发事件:Event(new UserRestored($user));(需自定义事件)
  • 覆盖 restore() 方法,在父类逻辑后追加业务代码
  • 改用 forceDelete() + 重新 create()(仅限简单场景,丢失自增 ID 和关联关系)

查询时容易漏掉 withTrashed()onlyTrashed()

默认所有 Eloquent 查询都会自动加 WHERE deleted_at IS NULL,这是隐式行为。这意味着 User::where('name', 'John')->get() 永远不会返回已软删除的记录——哪怕你心里清楚“这里应该包含回收站里的”。

使用场景判断要点:

  • 后台列表页要显示「全部/仅启用/已删除」三个 Tab → 分别用 all()withoutTrashed()onlyTrashed()
  • 关联查询默认不包含软删除子记录:$user->posts 不会返回已软删除的 Post,需在关系定义里加 ->withTrashed()
  • 软删除模型做 belongsTo 关联时,若外键指向一个已软删除的父记录,$post->user 会返回 null(因为关联查询也受软删除限制)

最常被忽略的一点:软删除字段本身可被搜索,但必须显式放开。比如想查「最近7天被删除的用户」,得写 User::onlyTrashed()->whereDate('deleted_at', '>=', now()->subWeek())->get(),而不是靠 whereNotNull('deleted_at') —— 后者绕过了软删除作用域,可能混入其他业务字段为 NULL 的脏数据。

text=ZqhQzanResources