如何在Laravel中使用whereHas查询满足特定关联条件的Task记录
Laravel Eloquent 实现Task查询需求
需求回顾
数据库结构:
scripts (id, parent_id, name) tasks (id, script_id, name)
需要查询满足以下任一条件的Task:
- 关联的Script的
parent_id为null - 存在Script记录,其
parent_id等于该Task的script_id(即tasks.script_id = scripts.parent_id)
实现方案
方案一:直接使用whereExists构造子查询
无需额外定义关联,直接通过子查询匹配条件:
use Illuminate\Database\Eloquent\Builder; use Illuminate\Support\Facades\DB; $tasks = Task::query() ->where(function (Builder $query) { // 条件1:关联的script无父级 $query->whereHas('script', fn (Builder $subQuery) => $subQuery->whereNull('parent_id')) // 条件2:当前script是其他script的父级 ->orWhereExists(fn (Builder $subQuery) => $subQuery ->select(DB::raw(1)) ->from('scripts') ->whereColumn('scripts.parent_id', 'tasks.script_id') ); }) ->get();
方案二:利用Eloquent关联简化代码
如果你的Script模型已定义children关联(表示该script的子script),可以用更简洁的写法:
首先在Script.php中定义关联:
// app/Models/Script.php public function children() { return $this->hasMany(Script::class, 'parent_id'); }
然后编写查询代码:
use Illuminate\Database\Eloquent\Builder; $tasks = Task::query() ->where(function (Builder $query) { $query->whereHas('script', fn (Builder $subQuery) => $subQuery->whereNull('parent_id')) ->orWhereHas('script.children'); }) ->get();
说明
- 两种方案逻辑完全等价,均可满足查询需求
- 方案一无需额外定义关联,适合临时查询场景;方案二代码更简洁,适合需要多次使用该关联的场景
内容的提问来源于stack exchange,提问作者Alexxosipov
相关产品推荐
相关产品推荐

