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

怎么给模型加软删除?
直接在模型里用 SoftDeletes trait,别漏了数据库字段。Laravel 不会自动帮你加 deleted_at 字段,手抖没加,后面查不到软删数据,也恢复不了。
- 在模型类顶部加上
use SoftDeletes; - 确保对应数据表有
deleted_at字段,类型是TIMESTAMP NULL(MySQL)或datetime null(SQLite/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,跳过模型)
delete 前确认用的是哪个层面的 API。










