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

Laravel Eloquent:如何在Booking模型中获取positions->areas->scopes数据

实现Booking模型直接关联获取Scopes数据

先梳理并补全基础关联

首先确保各模型的基础关联定义正确,对应你的多对多中间表结构:

Position 模型

// 与 Area 多对多关联,中间表 position_areas
public function areas()
{
    return $this->belongsToMany(Area::class, 'position_areas');
}

// 关联所属 Booking(假设一个 Position 对应一个 Booking)
public function booking()
{
    return $this->belongsTo(Booking::class);
}

Area 模型

// 与 Position 多对多关联
public function positions()
{
    return $this->belongsToMany(Position::class, 'position_areas');
}

// 与 Scope 多对多关联,中间表 area_scopes
public function scopes()
{
    return $this->belongsToMany(Scope::class, 'area_scopes');
}

Booking 模型

先定义与 Position 的基础关联:

// 一个 Booking 拥有多个 Position
public function positions()
{
    return $this->hasMany(Position::class);
}

实现直接加载 Scopes 的两种方式

根据你的 Laravel 版本选择对应方案:

方案一:Laravel 9+ 推荐使用 through 多层关联

Laravel 9 及以上支持通过 through 直接定义跨多层多对多的关联,代码最简洁:

public function scopes()
{
    return $this->belongsToMany(Scope::class)->through([Position::class, Area::class]);
}

定义完成后,直接执行 $booking->load('scopes') 就能获取所有关联的 Scope 数据,也可以直接访问 $booking->scopes 拿到集合。

方案二:兼容 Laravel 8 及以下版本

通过自定义关联查询或访问器实现:

方式1:自定义关联查询
public function scopes()
{
    return Scope::query()
        ->join('area_scopes', 'area_scopes.scope_id', '=', 'scopes.id')
        ->join('areas', 'areas.id', '=', 'area_scopes.area_id')
        ->join('position_areas', 'position_areas.area_id', '=', 'areas.id')
        ->join('positions', 'positions.id', '=', 'position_areas.position_id')
        ->where('positions.booking_id', $this->id)
        ->select('scopes.*')
        ->distinct(); // 去重,避免同一 Scope 重复返回
}
方式2:访问器实现惰性加载
public function getScopesAttribute()
{
    return $this->positions->flatMap(function ($position) {
        return $position->areas->flatMap(function ($area) {
            return $area->scopes;
        });
    })->unique('id');
}

这种方式需要先预加载嵌套关联避免重复查询:

$booking->load('positions.areas.scopes');
// 之后直接访问 $booking->scopes 即可

常见排查点

  • 确认中间表字段:position_areas 需包含 position_id、area_id;area_scopes 需包含 area_id、scope_id,字段类型与对应模型主键一致。
  • 模型主键非 id 时,需在模型中指定 protected $primaryKey = '你的主键名'。
  • 出现重复数据时,记得添加 distinct() 或 unique('id') 去重。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.31 21:05:19