Laravel怎么使用软删除功能 _ Laravel SoftDeletes模型配置方法【技巧】

3次阅读

在模型中使用Softdeletes trait并添加deleted_at字段实现软删除,查询默认过滤已软删数据,需withTrashed()等方法显式获取,关联关系和批量操作需特别处理以防状态不一致。

Laravel怎么使用软删除功能 _ Laravel SoftDeletes模型配置方法【技巧】

怎么给模型加软删除?

直接在模型里用 SoftDeletes trait,别漏了数据库字段。laravel 不会自动帮你加 deleted_at 字段,手抖没加,后面查不到软删数据,也恢复不了。

  • 在模型类顶部加上 use SoftDeletes;
  • 确保对应数据表有 deleted_at 字段,类型是 timestamp NULLmysql)或 datetime nullsqlite/postgresql
  • 如果用 php artisan make:migration 加字段,推荐写成:
    php artisan make:migration add_deleted_at_to_users_table --table=users

    然后在迁移里用 $table->softDeletes();

  • 已有数据的表,加完字段后记得跑 php artisan migrate,否则模型调 delete() 会报错说字段不存在

软删除后查询为什么查不到?

因为 Laravel 默认自动过滤掉 deleted_at IS NOT NULL 的记录——这是设计,不是 bug。但新手常以为“删了就该看不见”,结果发现 User::all() 看不到已软删的用户,误以为删失败了。

  • 查全部(含已软删):用 User::withTrashed()->get()
  • 只查已软删的:用 User::onlyTrashed()->get()
  • 恢复单条:先 $user->restore(),不是 save() 或手动设 deleted_at = null
  • 注意:find()first() 这些方法默认也走软删除过滤,要查软删记录必须显式加 withTrashed()

软删除和关联关系怎么处理?

默认情况下,父模型软删除,子模型不会跟着软删;反过来,子模型软删也不影响父模型查询。想联动,得手动配,而且容易漏掉 withTrashed() 导致关联查空。

  • 外键字段本身不参与软删除逻辑,所以 belongsTo 关系查不到已软删的父级,除非在关系定义里加 ->withTrashed()
  • 一对多场景下,如果想“软删文章时也软删评论”,不能靠数据库级级联,得重写模型的 deleting 事件
    protected static function booted() { static::deleting(function ($post) { $post->comments()->update(['deleted_at' => now()]); }); }
  • withTrashed() 只影响当前查询链,不自动透传到嵌套关系里,比如 Post::withTrashed()->with('comments') 仍只会查未软删的评论,要写成 Post::withTrashed()->with(['comments' => function ($q) { $q->withTrashed(); }])

软删除会影响哪些 Eloquent 方法?

不是所有方法都尊重软删除,有些行为反直觉。比如 forceDelete() 是真删,但 truncate() 完全绕过模型生命周期,直接清表——软删字段白加。

  • delete() → 写 deleted_at 时间戳(软删)
  • forceDelete() → 执行 DELETE FROM(真删)
  • restore() → 清空 deleted_at,仅对已软删记录有效
  • truncate() → 不触发模型事件,不走软删除逻辑,慎用
  • 批量操作如 User::where(...)->delete() 仍是软删;但 User::query()->where(...)->delete() 是真删(用了 Query Builder,跳过模型)

软删除看着简单,真正踩坑多在关联查询和批量操作上,尤其是团队协作时有人用模型实例删、有人用 Query Builder 删,数据状态就容易不一致。记得每次写 delete 前确认用的是哪个层面的 API。

text=ZqhQzanResources