TP8中with()在find()/select()中失效,须改用load()分步加载;field()不支持点号嵌套裁剪,需在关联定义或with闭包中指定字段;多层关联须逐级load;分页+关联推荐用join替代with()。

TP8中with()失效,必须改用load()
TP6写法 User::with('posts')->find(1) 在TP8里查不到关联数据,不是bug,是设计变更。TP8取消了with()在find()/select()链式调用中的预载行为,只保留“查询后加载”语义。
正确做法是分两步:
- 先查主模型:
$user = User::find(1); - 再显式加载:
$user->load('posts');或带条件:$user->load(['posts' => function($q) { $q->where('status', 1); }]); - 如果漏掉
load()这步,$user->posts永远是null,且不报错、无日志提示——这是最常踩的静默坑
关联字段裁剪不能再用主模型field()点号语法
User::with('profile')->field('id,name,profile.nickname') 在TP8会直接报错或静默忽略profile.nickname,因为field()只解析当前模型字段,不识别点号嵌套。
字段裁剪只能在两个位置生效:
- 关联定义内部硬编码:
public function profile() { return $this->hasOne(Profile::class)->field(['user_id', 'nickname', 'avatar']); }(注意user_id外键必须显式包含) - 或
with()闭包中动态指定:User::with(['profile' => function($q) { $q->field(['user_id', 'nickname']); }])->find(1) - 闭包里不能写
profile.nickname,只写字段名;多个关联要各自写闭包,不能复用同一个$q
多层关联必须逐级load,不能靠with嵌套
TP6支持with(['order' => function($q) { $q->with('items'); }]),TP8不认这种写法。嵌套关联必须手动逐层load:
- 先
$order = Order::find(123); - 再
$order->load('items'); - 如果
items还要查sku,得再$order->items->load('sku');(注意是集合对象上的方法) - 没有“一次性三级预载”的语法糖,强行嵌套会返回空或报
Call to undefined method
分页+关联在TP8仍需绕开with(),优先用join
User::with('posts')->paginate(10) 在TP8依然存在分页总数不准、关联数据缺失的问题,根本原因是paginate()底层COUNT不感知关联条件。
稳定方案仍是显式join:
-
User::alias('u')->join('posts p', 'u.id = p.user_id AND p.status = 1')->field('u.*, p.title as post_title')->distinct(true)->count('u.id')算总数 - 再同结构查数据,
->paginate(10)才可靠 - 排序字段来自关联表时(如
ORDER BY p.created_at),必须确保该字段在join中被选中且有索引,否则性能骤降
复杂嵌套(如User→Order→Item)几乎没法靠模型链式搞定,这时候别硬扛,直接上Db::table()->join()更省心。

















