tp6模型关联查询需定义清晰、调用简洁、字段可控、层级明确;通过with加载关联、闭包筛选字段、嵌套with处理多层关系,并用withcount优化统计。

TP6 接口开发中做模型关联查询,核心是“定义清楚、调用简洁、字段可控、层级明确”。不靠手写 SQL,也能高效拿到嵌套数据。
一、基础关联定义要到位
关联不是临时拼的,得在模型里提前声明。比如用户表 User 和资料表 Profile 是一对一:
- 在
User模型中写:public function profile() { return $this->hasOne(Profile::class, 'user_id'); } - 在
Profile模型中写:public function user() { return $this->belongsTo(User::class, 'user_id'); } - 外键名、主键名必须和数据库字段严格对应,否则
with查不到数据
二、接口中用 with 加载关联数据
控制器或逻辑层直接调用,一行代码就能带出关联字段:
-
$users = User::with('profile')->select();—— 返回每个用户 + 对应 profile 数据 - 支持闭包定制:
User::with(['profile' => function($q) { $q->field('id, name, age'); }])->select(); - 多个关联一起查:
with(['profile', 'posts', 'comments']),TP6 自动合并为最少查询次数
三、多层关联必须用 with 嵌套,不能用 withJoin
比如 canxunDanwei → school → category 这种三级结构:
-
withJoin只支持单层 LEFT JOIN,无法穿透到第三级 - 正确写法是:
->with(['canxunDanwei' => function($q) { $q->with(['dwJibie']); }]) - 注意:如果在中间层用了
field()(如只选id,title),会把下一层dwJibie的字段过滤掉;需要多层数据时,建议去掉field或显式包含子关联字段
四、关联字段筛选与性能兼顾
接口返回不能无脑全字段,但也不能误伤关联结构:
- 想限制主表字段?用
field('id,name,created_at')放在with前面即可 - 想限制关联表字段?必须在
with的闭包里用$query->field() - 要统计数量(比如用户有多少文章)?优先用
withCount('posts'),生成一条 JOIN 查询,避免 N+1 - 复杂条件统计(如只算 status=1 的文章数):
withCount(['posts' => function($q) { $q->where('status', 1); }])











