如何逐级删除Eloquent关联子模型?层级为Category=>Course=>Chapter=>Exam
解决方案:删除Category时级联删除关联子模型
针对删除Category时同步删除关联的Course、Chapter、Exam的需求,提供三种实用方案:
1. 数据库级联删除(推荐)
直接在数据库迁移中设置外键的级联删除规则,这是性能最高的方案,由数据库自动处理删除逻辑。
修改迁移文件:
- Course 迁移:给
category_id字段添加级联删除约束
$table->foreignId('category_id') ->constrained() ->onDelete('cascade');
- Chapter 迁移:给
course_id字段添加级联删除约束
$table->foreignId('course_id') ->constrained() ->onDelete('cascade');
- Exam 迁移:给
chapter_id字段添加级联删除约束
$table->foreignId('chapter_id') ->constrained() ->onDelete('cascade');
修改后执行迁移更新数据库,之后删除Category时,数据库会自动递归删除所有关联的Course、Chapter、Exam。
2. 模型事件处理
如果需要在删除前执行额外业务逻辑(比如记录日志),可以在Category模型中通过deleting事件实现级联删除:
// Category 模型 protected static function boot() { parent::boot(); static::deleting(function ($category) { // 从最底层的Exam开始批量删除 $category->courses()->each(function ($course) { $course->chapters()->each(function ($chapter) { $chapter->exams()->delete(); }); $course->chapters()->delete(); }); // 最后删除关联课程 $category->courses()->delete(); }); }
注意:使用
关联()->delete()而非关联->delete(),前者生成批量SQL语句,性能更优。
3. 控制器手动删除
在删除Category的控制器方法中,手动按层级删除关联模型:
// CategoryController public function destroy(Category $category) { // 1. 删除所有关联的Exam Exam::whereIn('chapter_id', function ($query) use ($category) { $query->select('id') ->from('chapters') ->whereIn('course_id', $category->courses->pluck('id')); })->delete(); // 2. 删除所有关联的Chapter Chapter::whereIn('course_id', $category->courses->pluck('id'))->delete(); // 3. 删除所有关联的Course $category->courses()->delete(); // 4. 删除Category本身 $category->delete(); return redirect()->back()->with('success', '分类及关联内容已删除'); }
方案对比
- 数据库级联删除:性能最优,无需额外代码,适合无额外业务逻辑的场景。
- 模型事件:适合需要在删除前后执行自定义逻辑的场景,代码耦合在模型中。
- 手动删除:逻辑清晰,适合控制器中需要灵活处理的场景。
内容的提问来源于stack exchange,提问作者Gagan Sharma
相关产品推荐
相关产品推荐

