Laravel中如何不使用JOIN通过Eloquent附加子模型字段到父模型
Eloquent 父子关联字段平铺挂载方案
核心结论
Eloquent原生支持该需求,不需要使用JOIN查询,实现逻辑和已有的withCount()方法完全同源,最终可实现子表字段与父模型字段平级挂载,无嵌套关联结构。
实现方式
Laravel 9 及以上版本(原生便捷方法)
直接调用withCount()底层的通用关联聚合方法withAggregate()即可,用法和withCount()几乎一致,支持直接提取子表任意字段挂载到父模型顶层属性:
// 需提前在Types模型中定义好typeChild关联(hasOne/belongsTo类单结果关联) Types::query() ->withAggregate('typeChild', 'rank as child_rank') ->get()
该方法底层生成的是关联相关子查询,和withCount()的执行逻辑完全相同,不会产生JOIN语句。返回结果中child_rank字段会和Types模型自身的id、名称等原生字段平级,不会嵌套在typeChild关联数组下,完全符合平级挂载的结构要求。
Laravel 8 及更早版本
低版本没有内置withAggregate()方法时,可直接通过查询构造器的addSelect()方法手动追加关联子查询,同样不依赖JOIN,实现效果完全一致:
Types::query() ->addSelect([ 'child_rank' => function ($query) { // 直接复用模型内已定义的typeChild关联逻辑,无需重复编写外键匹配条件 return (new Types())->typeChild() ->getQuery() ->select('rank') ->limit(1); } ]) ->get()
注意事项
- 若
typeChild是hasMany一对多关联,需要在子查询中增加orderBy()等筛选规则,明确指定要取哪一条子记录的字段,避免子查询返回多行触发SQL错误 - 如果不需要调用完整的子关联数据,无需额外调用
with()做预加载,子查询可独立完成字段取值 - 该方案的性能表现和
withCount()完全一致,无额外性能开销
内容的提问来源于stack exchange,提问作者Aleks
相关产品推荐
相关产品推荐

