Laravel:单次关联查询筛选拥有福特汽车的Person用户
解决Laravel中筛选关联模型并避免N+1查询的问题
嘿,你遇到的这个N+1查询问题很常见,我来帮你搞定它!
首先,你当前的代码用whereHas确实能筛选出所有拥有福特汽车的用户,但循环里调用$person->cars()->get()会导致每遍历一个用户就执行一次数据库查询——这就是典型的N+1问题(1次查用户,N次查每个用户的汽车)。
优化方案1:约束预加载(推荐,代码清晰且性能优秀)
我们可以用with()方法来预加载符合条件的关联汽车,同时保留whereHas的筛选逻辑,这样整个过程只会执行2次数据库查询(1次查符合条件的用户,1次批量查这些用户的福特汽车),完美避免N+1。
修改后的代码如下:
$persons = Person::whereHas('cars', function ($query) { $query->where('mark', 'ford'); })->with(['cars' => function ($query) { // 只预加载该用户的福特汽车 $query->where('mark', 'ford'); }])->get(); // 遍历的时候直接访问属性,不用再调用get() foreach ($persons as $person) { foreach($person->cars as $car) { print $person->name . " has a " . $car->mark . "\n"; } }
优化方案2:使用JOIN实现单次查询(适合仅需用户信息的场景)
如果你确实需要单次数据库查询完成,也可以用join来关联两张表,不过这种方式如果用户有多辆福特车,会返回重复的用户记录,需要用distinct()去重:
// 仅获取拥有福特车的用户信息(不含汽车详情) $persons = Person::select('persons.*') ->join('cars', 'persons.id', '=', 'cars.person_id') ->where('cars.mark', 'ford') ->distinct() ->get();
但要注意,这种方式没法直接拿到用户对应的福特汽车详情,如果需要同时获取用户和汽车信息,还是第一种约束预加载的方案更实用。
内容的提问来源于stack exchange,提问作者user1985273
相关产品推荐
相关产品推荐

