laravel 10 与 11 中 softdeletes trait 行为完全一致:均不自动注册全局作用域,必须手动在 boot() 中调用 static::addglobalscope(new softdeletingscope);find()/first() 等方法均不走该作用域,withtrashed() 和 restore() 等逻辑无版本差异。

从 Laravel 10 到 11,SoftDeletes trait 本身没有新增或删减方法,核心差异不在 trait 内部,而在于框架对全局作用域注册行为的默认策略是否延续——答案是:完全一致,且都不自动注册。
软删除作用域必须手动注册,10 和 11 都一样
Laravel 9 起已移除 SoftDeletes trait 的隐式全局作用域注册;Laravel 10 和 11 均继承该设计,不会因版本升级自动生效。若模型只写 use SoftDeletes; 却未在 boot() 中调用 static::addGlobalScope(new SoftDeletingScope()),则:
-
User::all()返回全部记录(含deleted_at非空的) -
User::find(1)和User::where('id', 1)->first()行为一致,都不过滤软删数据 -
delete()仍会更新deleted_at,但查询端无任何过滤逻辑
find()、findOrFail()、first() 等主键/条件直查方法始终不走全局作用域
这不是版本差异,而是 Laravel 查询构造器的设计原则:所有基于主键的快捷方法(find、findOrFail、first、value 等)均绕过全局作用域,包括软删除作用域。因此:
-
User::find(1)永远查不到已软删记录(返回null),无论 Laravel 10 还是 11 - 要验证作用域是否生效,必须用
User::where('id', 1)->first()或User::withTrashed()->find(1) - 关联加载(如
$user->posts)也独立于父模型作用域,需在关联定义或子模型中单独控制
withTrashed() 和 onlyTrashed() 的行为完全兼容,无版本变动
这两个方法在 10 和 11 中语义与实现完全一致:
-
withTrashed():临时移除WHERE deleted_at IS NULL条件,查全部 -
onlyTrashed():替换为WHERE deleted_at IS NOT NULL,仅查软删记录 - 它们影响
get()、first()、count()、exists()等所有终结方法,但不影响关联预加载中的子查询 - 例如:
User::withTrashed()->with('posts')->get()中的posts仍按Post模型自身的软删除配置执行
restore() 和 forceDelete() 的失败原因在两版中也完全相同
静默恢复失败、forceDelete() 报错等现象,根源与版本无关,集中在三类共性问题:
-
deleted_at字段被设为NOT NULL或带DEFAULT CURRENT_TIMESTAMP,导致UPDATE ... SET deleted_at = NULL失败 - 模型中定义了
restoring事件回调并返回false或抛出未捕获异常 - 在事务中调用
restore()后未提交,或外层事务回滚
这些在 Laravel 10 和 11 中表现一致,调试方式也完全通用。











