Laravel基于有向无环图递归关系的任务依赖层级查询实现
Laravel 按依赖层级查询任务实现方案
首先建议先优化原关联定义,直接通过多对多关联获取关联的任务实例,无需手动操作中间表:
// Task 模型中新增/调整关联 // 当前任务依赖的父任务 public function parentTasks() { return $this->belongsToMany(Task::class, 'dependent_tasks', 'task_id', 'dependent_id'); } // 依赖当前任务的子任务 public function childTasks() { return $this->belongsToMany(Task::class, 'dependent_tasks', 'dependent_id', 'task_id'); }
方案1:固定层级查询(适合层级少的场景)
直接按层级逐层查询,符合你给出的3层查询需求:
// 第一层:ID为2、5的任务 $level1 = Task::whereIn('id', [2, 5])->get(); $level1Ids = $level1->pluck('id'); // 第二层:第一层任务的直接子任务 $level2 = Task::whereHas('parentTasks', function ($query) use ($level1Ids) { $query->whereIn('tasks.id', $level1Ids); })->get(); $level2Ids = $level2->pluck('id'); // 第三层:第二层任务的直接子任务 $level3 = Task::whereHas('parentTasks', function ($query) use ($level2Ids) { $query->whereIn('tasks.id', $level2Ids); })->get(); // 按层级返回结果 $tasksByLevel = [ 1 => $level1, 2 => $level2, 3 => $level3 ];
方案2:递归CTE查询(适合层级不固定的场景)
如果后续层级可能变动,使用公共表表达式递归查询,支持任意层级的依赖查询(要求数据库支持CTE,如MySQL 8.0+、PostgreSQL等):
$tasksByLevel = Task::query() ->selectRaw('tasks.*, 1 as level') ->whereIn('id', [2, 5]) ->unionAll( Task::query() ->selectRaw('tasks.*, cte.level + 1 as level') ->join('dependent_tasks as dt', 'dt.dependent_id', '=', 'tasks.id') ->join('cte', 'cte.id', '=', 'dt.task_id') ) ->withRecursiveExpression('cte') ->orderBy('level') ->get() ->groupBy('level');
查询结果会自动按level字段分组,直接通过$tasksByLevel[1]、$tasksByLevel[2]即可拿到对应层级的任务集合。
注意事项
如果保留原有的中间表关联定义,只需把上述查询中关联部分替换为对dependents/depends_on中间表的ID筛选即可,逻辑完全一致。由于你已经确认关联为有向无环图结构,无需额外处理循环依赖问题。
内容的提问来源于stack exchange,提问作者3yad
相关产品推荐
相关产品推荐

