Laravel模型关联问题:如何获取指定Branch下的关联Category
前置:先补全模型的基础关联定义
写查询前先确保三个模型的基础关联定义正确,这是所有Eloquent关联查询的基础:
Branch模型定义和Item的一对多关联:
// app/Models/Branch.php public function items() { return $this->hasMany(Item::class); }
Item模型定义两个多对一关联,分别对应所属Branch和所属Category:
// app/Models/Item.php public function branch() { return $this->belongsTo(Branch::class); } public function category() { return $this->belongsTo(Category::class); }
两种可落地的查询实现方案
方案1:基于链式关联穿透的查询(适合轻量场景)
如果已经拿到了指定的Branch实例,可以通过穿透关联获取旗下所有Item对应的Category,全程不需要写原生SQL:
// 先获取目标Branch实例 $branch = Branch::find($指定分支ID); // 预加载关联的Category,避免N+1查询,最后做去重处理 $categoryList = $branch->items() ->with('category') ->get() ->pluck('category') ->unique('id'); // 按分类ID去重,避免同一个分类对应多个Item时重复返回
这种写法的灵活性更高,后续如果要给Item加过滤条件(比如只拿上架状态的Item),直接在items()链式调用后面追加where条件就行。
方案2:定义远层关联的查询(适合高频查询场景)
如果“获取分支下全部分类”是业务里的高频操作,建议在Branch模型上直接定义远层一对多关联,查询效率更高,代码更简洁。
首先在Branch模型里补充关联方法:
// app/Models/Branch.php public function categories() { // 关联路径:Branch -> 中间表Item -> 最终目标Category return $this->hasManyThrough( Category::class, // 最终要查询的模型 Item::class, // 中间关联模型 'branch_id', // 中间模型Item上存储的Branch外键 'id', // Category表上的主键,对应Item表的category_id 'id', // Branch表上的主键 'category_id' // 中间模型Item上存储的Category外键 )->distinct(); // 直接在数据库层面去重,避免重复返回同一个分类 }
定义完成后,查询逻辑可以简化为一行:
// 直接获取指定分支下的所有去重后Category列表 $categoryList = Branch::find($指定分支ID)->categories;
如果需要给分类加额外的过滤条件(比如只拿启用状态的分类),也可以直接链式追加:
$activeCategoryList = Branch::find($指定分支ID) ->categories() ->where('status', 1) ->get();
避坑提示
- 所有需要关联多表拿集合的场景,都要记得做去重,不然同一个分类下挂了10个Item,就会返回10条重复的分类数据,优先用数据库层面的*
distinct()*做去重,比PHP内存里的unique()性能更好。 - 不要在遍历Item集合的时候单独取每条的Category,没加预加载的话会触发N+1查询问题,数据量稍大就会导致接口响应变慢。
- 如果业务只需要Category的列表数据,不需要加载Item的全量字段,优先用远层关联的写法,SQL查询的开销会比“先查全量Item再提取分类”低很多。
内容的提问来源于stack exchange,提问作者debasish nandi
相关产品推荐
相关产品推荐

