Laravel Eloquent嵌套With关联查询:如何将父模型列值作为子查询Where条件
解决Laravel嵌套关联查询中传递父模型列到子查询的问题
没问题,我完全理解你想要高效获取Category->Brands->Items嵌套结构的需求——循环逐个查询确实太低效了,咱们可以用Laravel的关联约束特性来实现批量、高效的查询,不用走N+1的弯路。
首先,你当前尝试的whereColumn('category_id', 'categories.id')思路是对的,但需要注意嵌套关联中的查询上下文,我来给你调整出正确的写法:
Category::with(['brands' => function ($brandQuery) { // 预加载每个品牌下,属于当前分类的商品 $brandQuery->with(['items' => function ($itemQuery) { // 通过whereColumn关联外层分类表的id和商品的category_id // 这里Laravel会自动处理表的关联关系,确保每个商品都属于当前父分类 $itemQuery->whereColumn('items.category_id', 'categories.id'); }]); // 可选:如果你只想保留那些有对应分类商品的品牌,加上这个whereHas约束 $brandQuery->whereHas('items', function ($itemQuery) { $itemQuery->whereColumn('items.category_id', 'categories.id'); }); }])->get();
为什么这个方案高效?
这个写法只会执行3次数据库查询:
- 先获取所有目标分类
- 批量获取这些分类关联的所有品牌
- 批量获取这些品牌下、对应所属分类的商品
完全避免了循环查询带来的N+1性能问题,和你之前的低效方案比,性能提升非常明显。
额外优化:指定需要的字段
如果不需要模型的所有字段,还可以通过select指定需要的列,进一步减少数据传输量:
Category::select('id', 'name') // 只选择分类的必要字段 ->with(['brands' => function ($brandQuery) { $brandQuery->select('id', 'name') ->with(['items' => function ($itemQuery) { $itemQuery->select('id', 'name', 'brand_id', 'category_id') ->whereColumn('items.category_id', 'categories.id'); }]); }])->get();
原理说明
whereColumn在这里的作用是比较两个表的列值,而不是用固定值去匹配。在嵌套预加载的上下文里,Laravel会自动处理外层categories表和内层items表的关联,确保每个分类下的商品都属于该分类,完美实现你想要的嵌套数据结构。
这样写出来的结果就是每个Category对象下,包含关联的Brands,每个Brand下又只包含属于当前Category的Items,完全符合你的需求。
内容的提问来源于stack exchange,提问作者Анжел Миленов
相关产品推荐
相关产品推荐

