You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Laravel多层关联记录预加载实现咨询

问题分析与正确写法

你担心的点完全正确!当前的写法Services::with('service_journeys', 'service_journey_sections')->get();确实存在问题——它会把service_journey_sections当成Service模型的直接关联来尝试加载,但实际上这个关联是属于service_journeys的子层级(祖孙关系),并非平级的直接关联。

为什么原写法不对?

如果你的Service模型里没有定义service_journey_sections这个直接关联方法,执行这段代码会直接抛出BadMethodCallException,提示找不到该关联;就算你误打误撞定义了这个直接关联,加载出来的也会是和Service直接绑定的sections,而非通过ServiceJourney关联的孙级数据,完全不符合你的需求。

正确的嵌套预加载写法

要实现加载所有Service及其下属的ServiceJourneys,再到每个ServiceJourney的ServiceJourneySections,你需要用Laravel的嵌套预加载语法,有两种常用方式:

1. 简洁的点语法(适合无额外查询约束的场景)

Services::with('service_journeys.service_journey_sections')->get();

这种写法清晰表达了层级关系:加载Service的service_journeys关联,同时加载每个service_journey的service_journey_sections关联。

2. 数组嵌套写法(适合需要给子关联加查询约束的场景)

如果需要对某个层级的关联添加筛选、排序等条件,可以用数组嵌套的闭包写法:

Services::with([
    'service_journeys' => function ($query) {
        // 比如给service_journeys按出发时间排序
        $query->orderBy('departure_time', 'asc');
    },
    'service_journeys.service_journey_sections' => function ($query) {
        // 只加载启用状态的service_journey_sections
        $query->where('is_active', true);
    }
])->get();

验证是否正确加载

加载完成后,可以通过以下方式验证:

// 取第一个Service,查看其第一个ServiceJourney下的sections
dd($services->first()->service_journeys->first()->service_journey_sections);

同时可以查看SQL日志,确认只执行了3条查询:

  • 1条查询所有Services
  • 1条查询所有关联的ServiceJourneys
  • 1条查询所有关联的ServiceJourneySections
    这说明预加载生效,避免了N+1查询问题。

内容的提问来源于stack exchange,提问作者Brad

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.13 08:25:30