Laravel 如何按所属州查询关联用户 无需单独调用City模型
Eloquent 查询指定州下关联城市对应用户的优化实现
问题背景
- 表结构关联关系:
users表包含外键字段city_id,关联城市表主键cities表包含外键字段state_id,关联所属州的主键
- 需求:在现有用户筛选逻辑中增加按州过滤能力,筛选出属于指定州下所有城市对应的用户
初始代码框架
$users = User::role('company') ->when((int) $state, function ($query, $state) { // 待实现的按州筛选逻辑 }) ->when((int) $city, function ($query, $city) { return $query->where('city_id', $city); }) ->get();
已尝试的实现
原实现逻辑:先单独调用City模型查出对应州下所有城市的id集合,再通过
whereIn匹配用户的city_id字段
$users = User::role('company') ->when((int) $state, function ($query, $state) { $cities = City::where('state_id', $state) ->pluck('id') ->toArray(); return $query->where('city_id', $cities); }) ->when((int) $city, function ($query, $city) { return $query->where('city_id', $city); }) ->get();
该方案可以正常返回结果,但会产生两次数据库交互(一次拉取城市id数组到PHP端、一次查询用户),属于冗余查询,需要优化为无单独City模型调用的实现方式。
优化实现方案
两种无需单独调用City模型的实现方式都可以完成单SQL筛选,避免冗余查询:
方案1:基于模型关联的whereHas实现
前提:User模型已定义与City的关联方法(即city()方法返回belongsTo(City::class))
$users = User::role('company') ->when((int) $state, function ($query, $state) { // 直接通过关联关系完成筛选,不需要手动查询城市id集合 $query->whereHas('city', function ($cityQuery) use ($state) { $cityQuery->where('state_id', $state); }); }) ->when((int) $city, function ($query, $city) { return $query->where('city_id', $city); }) ->get();
- 特点:写法简洁,符合Eloquent的关联编程规范,所有筛选逻辑下推到数据库层,无多余PHP端数据处理。
方案2:子查询实现(无关联依赖)
如果不想依赖模型关联定义,可以直接通过闭包子查询完成城市id匹配,效果与方案1完全一致:
$users = User::role('company') ->when((int) $state, function ($query, $state) { $query->whereIn('city_id', function ($subQuery) use ($state) { // 子查询直接在数据库层运行,不会将城市id数组拉取到PHP端 $subQuery->select('id') ->from('cities') ->where('state_id', $state); }); }) ->when((int) $city, function ($query, $city) { return $query->where('city_id', $city); }) ->get();
- 特点:不依赖模型关联定义,直接通过表结构实现筛选,执行效率与
whereHas基本一致。
内容的提问来源于stack exchange,提问作者Andreas Hunter
相关产品推荐
相关产品推荐

