Laravel怎么实现软删除_Laravel Eloquent SoftDeletes教程【恢复】

7次阅读

软删除未生效的根本原因是模型未同时满足三个条件:引入softdeletes trait、正确声明$dates或$casts、数据库deleted_at字段为NULLable timestamp/datetime;查询默认过滤软删数据,需withtrashed()等方法显式包含;restore()是实例方法且仅对软删记录有效;关联数据需手动处理。

Laravel怎么实现软删除_Laravel Eloquent SoftDeletes教程【恢复】

软删除字段没生效,deleted_at 始终为 null

根本原因通常是模型没真正启用软删除——不是加了 use SoftDeletes 就完事。laravel 要求模型同时满足三个条件:引入 trait、声明 $dates(或 Laravel 9+ 的 $casts)、数据库字段存在且类型正确。

  • deleted_at 字段必须是 Nullable timestampmysql)或 nullable datetime,不能是 StringInteger
  • Laravel 8 及以前需在模型中显式添加:protected $dates = ['deleted_at'];;Laravel 9+ 推荐用 protected $casts = ['deleted_at' => 'datetime'];
  • 如果用了自定义字段名(比如 is_deleted),SoftDeletes trait 不会识别——它只认 deleted_at

查询时查不到已软删除的数据,但业务需要“看到”它们

默认所有 Eloquent 查询都会自动加上 WHERE deleted_at IS NULL,这是软删除的核心机制,但也是最容易困惑的点:你以为数据“还在”,其实它已经被过滤掉了。

  • 要查包括已软删的记录,用 withTrashed()User::withTrashed()->find(123)
  • 只查已被软删的,用 onlyTrashed()User::onlyTrashed()->where('email', 'test@example.com')->get()
  • 注意:关联查询不会自动继承软删除状态,user->posts 默认不包含软删的 post,得手动在关系定义里加 ->withTrashed()

调用 restore() 没反应,或者报错 “Call to undefined method”

restore() 是实例方法,不是静态方法。常见错误是直接在查询构造器上调用,比如 User::where('id', 1)->restore() —— 这会失败,因为 restore() 不在 Builder 类里。

  • 正确做法是先获取模型实例:User::withTrashed()->find(1)->restore()
  • 批量恢复必须用集合操作:User::onlyTrashed()->get()->each->restore(),不能用 update() 直接设 deleted_at = null,否则事件(如 restoring / restored)不会触发
  • 如果模型被硬删除过(即执行过 forceDelete()),restore() 无效——软删除只对曾经软删、未被强制清除的记录有效

软删除后关联数据没处理,外键约束或业务逻辑出问题

软删除只作用于当前模型,Eloquent 不会自动软删关联数据,也不会检查外键引用。这常导致“用户已删除,但他的订单还显示着”,或更糟:数据库级外键冲突(如果设了 ON DELETE CASCADE 但又想软删)。

  • 避免在数据库设 CASCADE 删除,软删除和物理级级联天然冲突
  • 需要联动软删时,手动处理:在模型的 deleting 事件里调用关联模型的 delete(),例如:$this->posts()->delete()
  • 查询带关联时,记得给关联也加软删除支持,比如在 Post 模型里同样启用 SoftDeletes,否则 $user->posts 仍可能返回已软删的 post(取决于关系定义是否加了 withTrashed()

软删除看着简单,真正落地时最麻烦的是边界:什么时候该查带删的、什么时候不该;事件触发时机是否符合预期;关联模型是否同步处理。这些地方一漏,数据状态就容易“半死不活”。

text=ZqhQzanResources