加了 SoftDeletes trait 还查不到 deleted_at 字段是因为该 trait 仅启用软删除逻辑,不自动添加数据库字段;必须手动创建迁移并使用 $table->softDeletes() 添加 deleted_at 字段。

为什么加了 SoftDeletes trait 还查不到 deleted_at 字段
因为 SoftDeletes 只是启用软删除逻辑,不会自动在数据库中添加 deleted_at 字段。必须手动迁移添加:
- 运行
php artisan make:migration add_deleted_at_to_users_table - 在迁移文件的
up()方法里写:public function up(Blueprint $table) { $table->softDeletes(); } - 执行
php artisan migrate
注意:如果表已存在且有数据,softDeletes() 会添加可为 NULL 的 deleted_at 字段;但不会修改已有记录的该字段值,所以历史数据默认不被视为“已删除”。
调用 delete() 后数据没消失但 where 查询查不到
这是软删除的预期行为:调用 $user->delete() 会把 deleted_at 设为当前时间戳,而非真正删掉行。Laravel 默认的 Eloquent 查询会自动加上 WHERE deleted_at IS NULL 条件。
- 想查出所有记录(含已软删除的):用
User::withTrashed()->get() - 只查已软删除的:用
User::onlyTrashed()->get() - 恢复单条:用
$user->restore()(会清空deleted_at) - 强制物理删除:用
$user->forceDelete()
注意:关联查询(如 $user->posts)默认也不会加载已软删除的关联记录,除非对应模型也用了 SoftDeletes 并显式调用 withTrashed()。
restore() 不生效或报错 “Call to undefined method”
常见原因有两个:
- 模型没 use
Illuminate\Database\Eloquent\SoftDeletestrait,只加了迁移字段没用 - 调用方式错误:比如对集合批量调用
restore()时没用each(),直接写$users->restore()会失败
正确批量恢复示例:
$users = User::onlyTrashed()->where('created_at', '<', now()->subWeek())->get();
$users->each->restore(); // 或 $users->each(function ($u) { $u->restore(); });
另外,如果模型启用了全局作用域(如多租户 scope),要确认 restore() 是否被拦截 —— 它不触发 creating/updating 等事件,但会触发 restoring 和 restored 事件。
软删除后关联数据怎么处理:级联 or 保留
Laravel 不自动处理软删除的关联级联。比如 User 软删除,它的 Post 记录默认仍可查(除非 Post 自己也用了 SoftDeletes)。
- 想让关联也软删除:需手动在模型事件里实现,例如监听
deleting事件,然后调用$this->posts()->update(['deleted_at' => now()]) - 想物理删除关联:监听
forceDeleted事件,再执行$this->posts()->forceDelete() - 避免误恢复时带出脏关联:恢复主模型前,先检查并同步恢复关联模型(需自行编码逻辑)
没有银弹方案。是否级联、怎么级联,得看业务——回收站功能通常要求“主模型恢复时,其软删除的子数据也一并恢复”,这必须自己控制,Eloquent 不代劳。











