Laravel链式Scope查询中如何获取whereHas返回的用户ID执行后续查询
问题解决实现
修正后可直接运行的Scope代码
public function scopeLoadAvailableAgents($query) { // Scope方法不要直接调用get(),保留链式调用能力,查询执行放在调用侧处理 return $query->whereHas('roles', function ($q) { $q->where('name', 'agent'); }) ->whereNotIn('id', function ($q) { // 直接查询agent_to_manager表中所有已绑定的user_id集合即可 $q->select('user_id') ->from(app(UserToManager::class)->getTable()); }); }
逻辑说明
- 第一层
whereHas已经完成了「筛选拥有agent角色的用户」的逻辑,此时查询构造器已经限定了仅符合角色要求的用户范围 - 第二层
whereNotIn不需要单独获取前面的用户id,Laravel会自动将外层用户表的id字段和子查询返回的user_id集合做匹配,自动过滤掉存在于agent_to_manager表中的用户
更简洁的推荐写法
可以通过Laravel的whereDoesntHave关联查询方法简化代码,首先需要在User模型中提前定义和UserToManager的关联:
// app/Models/User.php 中添加关联定义 public function managerBinding() { return $this->hasOne(UserToManager::class, 'user_id'); }
之后Scope可以简化为:
public function scopeLoadAvailableAgents($query) { return $query->whereHas('roles', fn($q) => $q->where('name', 'agent')) ->whereDoesntHave('managerBinding'); }
调用示例
在需要查询的位置调用即可,支持后续拼接其他查询条件:
// 查询所有符合要求的用户 $availableAgents = User::loadAvailableAgents()->get(); // 也支持拼接分页等其他逻辑 $availableAgents = User::loadAvailableAgents()->paginate(10);
注意事项
- 不要在Scope方法内部执行
get()等最终查询操作,否则会破坏链式调用能力,无法后续拼接其他查询条件 - 原写法的误区是误以为需要手动获取前面whereHas的查询结果传递给子查询,实际上whereNotIn会自动处理集合匹配逻辑,不需要手动传参绑定
内容的提问来源于stack exchange,提问作者Amiyo Ghosh
相关产品推荐
相关产品推荐

