
在 laravel 中,无需定义额外的模型方法,即可通过 withcount() 快速为查询结果添加关联模型的数量字段,避免 n+1 查询问题,提升性能。
在 Laravel 开发中,当需要查询某模型及其关联记录的数量(例如:每个城市拥有的手机号数量)时,切忌在模型中定义类似 mobile_count() 这样的普通方法并直接用于查询语句中——因为该方法返回的是整型值,无法被 Eloquent 的查询构建器识别,也无法参与 SQL 层面的聚合计算,强行调用会导致逻辑错误或运行时异常。
正确做法是利用 Laravel 内置的 withCount() 关系预加载计数功能。它会在底层自动生成 SELECT ... COUNT(*) 子查询或 LEFT JOIN + GROUP BY 语句,一次性高效获取主模型数据及关联统计值。
首先,确保你的 City 模型中正确定义了 hasMany 关系(建议使用复数形式命名,如 mobiles):
// app/Models/City.php
public function mobiles()
{
return $this->hasMany(Mobile::class);
}⚠️ 注意:无需也不应再定义 mobile_count() 这类非关系方法——它既不能被查询构造器使用,也无法自动注入到 JSON 响应中;withCount('mobiles') 会自动在结果对象上添加 mobiles_count 属性(Laravel 默认命名规则:关系名 + _count)。
然后,在控制器中重构查询逻辑:
public function findCityWithID($id)
{
// 使用 withCount 加载 mobiles 关联的数量
$cities = City::select('id', 'name', 'state_id')
->withCount('mobiles') // ✅ 自动生成 mobiles_count 字段
->where('state_id', $id)
->orderBy('name')
->get();
// 可选:显式映射为更清晰的键名(如需兼容前端字段约定)
$response = $cities->map(function ($city) {
return [
'id' => $city->id,
'name' => $city->name, // 注意:原答案中误写为 $city->state
'state_id' => $city->state_id,
'mobile_count'=> $city->mobiles_count, // Laravel 自动注入的属性
];
});
return response()->json($response);
}✅ 优势总结:
- 性能优异:单次 SQL 查询完成主表数据 + 关联计数,杜绝 N+1;
- 语法简洁:无需手动写子查询或 join;
- 类型安全:返回结果中 mobiles_count 是整型,可直接序列化;
- 可链式扩展:支持 withCount(['mobiles', 'users', 'posts']) 多关联计数。
? 小贴士:若需自定义计数字段名(如 mobile_count 而非 mobiles_count),可使用数组语法:
->withCount(['mobiles as mobile_count'])
此时访问 $city->mobile_count 即可。
至此,你已掌握 Laravel 中优雅、高效地为模型查询附加关联计数的标准实践。










