
本文详解如何在 laravel eloquent 中通过单次查询同时预加载模型的多个关联关系(包括多层嵌套关系),避免 n+1 查询问题,并提供正确语法、常见错误提示与最佳实践。
本文详解如何在 laravel eloquent 中通过单次查询同时预加载模型的多个关联关系(包括多层嵌套关系),避免 n+1 查询问题,并提供正确语法、常见错误提示与最佳实践。
在 Laravel 开发中,高效处理模型关联是提升应用性能的关键环节。当你需要从主模型(如 StoreStock)出发,同时获取其关联模型(如 Product)的多个子级关系(例如 price 和 masterlist),错误地链式调用 with() 或重复调用会导致语法错误或仅生效最后一个关系。
✅ 正确做法是:向 with() 方法传入一个字符串数组,每个元素为点号分隔的嵌套关系路径:
$storeStocks = StoreStock::with([
'product.price',
'product.masterlist'
])->get();该写法会一次性执行 3 条优化后的 SQL 查询(而非 N+1):
- 1 条查询所有 store_stock 记录;
- 1 条通过 product_id 关联批量查询对应 products;
- 1 条联合查询所有匹配的 prices 和 masterlists(Laravel 自动合并关联 ID 进行 IN 查询)。
⚠️ 常见误区提醒:
- ❌ 错误写法:StoreStock::with('product.price')->with('product.masterlist')->get()
→ 后者会覆盖前者,最终只加载 product.masterlist; - ❌ 错误写法:StoreStock::with('product.price', 'product.masterlist')->get()
→ with() 不接受多个独立字符串参数(PHP 会报错:Too many arguments); - ✅ 正确本质:with() 接收单一参数——array|string,多关系必须包裹在数组中。
? 进阶技巧:
你还可以混合加载一级和深层关系,例如:
StoreStock::with([
'product', // 一级关联
'product.price', // 二级
'product.masterlist.status', // 三级(假设 masterlist 有 status 关系)
'warehouse.location' // 另一个一级关联
])->get();? 总结:
始终将多个 eager-loaded 关系组织为索引数组传入 with();结合 ->load() 可在已有集合上按需补载(适用于条件分支场景);配合 dd($model->relations) 或 Laravel Telescope 验证是否真正预加载成功。合理使用此模式,可显著降低数据库查询次数,提升接口响应效率。










