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

如何在Eloquent嵌套预加载子查询中传递上层Product模型的id

解决方案

你不能直接在with预加载的闭包里拿到单个Product的id,因为Eloquent的预加载是批量查询逻辑:先查所有Product数据,再批量查关联的Local数据,再批量查关联的Presentation数据,全程只有3次查询,不是逐个Product查询,所以没有单独的$product_id变量可以直接调用。

你可以通过调整关联定义的方式完全避免手动传参的问题,也是性能最优的方案:

步骤1:给中间表模型LocalProduct添加关联

你的Presentation是关联中间表LocalProduct的,直接在LocalProduct模型中定义到Presentation的一对多关联即可:

// App/Models/LocalProduct.php
public function presentations()
{
    return $this->hasMany(Presentation::class);
}

步骤2:调整查询代码直接预加载中间表关联

因为中间表local_product本身就存储了对应的product_id和local_id,所以通过中间表加载的presentations天然就符合你要的过滤条件,不需要额外加where约束:

$products = Product::select('id', 'nombre')
    ->with(['locals' => function ($localsQuery) {
        $localsQuery->select('locals.id', 'descripcion')
            ->withPivot('id', 'is_active')
            // 直接预加载中间表的presentations关联
            ->with(['pivot.presentations' => function ($presentationsQuery) {
                $presentationsQuery->select(
                    'local_product_id',
                    'product_id',
                    'id',
                    'presentation',
                    'price'
                );
            }]);
    }])
    ->get();

return $products;

最终数据结构说明

查询完成后,你可以直接按下面的方式取到对应的数据,和你原来循环拼接的结果完全一致:

  • 每个Product实例下有locals属性,存储关联的门店列表
  • 每个Local实例下有pivot属性,对应中间表LocalProduct的实例
  • 每个pivot实例下有presentations属性,存储当前Product+当前Local对应的所有规格数据

替代方案:不想改关联定义的情况

如果不想新增关联,也可以用集合过滤的方式,预加载所有关联数据后再过滤,适合数据量不大的场景:

$products = Product::select('id', 'nombre')
    ->with(['locals' => function ($localsQuery) {
        $localsQuery->select('locals.id', 'descripcion')
            ->with(['presentations' => function ($presentationsQuery) {
                $presentationsQuery->select(
                    'presentations.local_id',
                    'presentations.product_id',
                    'presentations.id',
                    'presentation',
                    'price'
                );
            }]);
    }])
    ->get()
    // 集合层面过滤每个local下的presentations
    ->each(function ($product) {
        $product->locals->each(function ($local) use ($product) {
            $local->presentations = $local->presentations->where('product_id', $product->id)->values();
        });
    });

return $products;

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.09.26 18:36:04