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

如何通过一层1:1关系嵌套扩展Eloquent HasManyThrough关联

不要在关系方法里直接遍历$this->participants属性——只要访问不带括号的关联属性就会立刻执行数据库查询,返回的是普通集合,不是可构建查询的关系实例,自然没法保留链式调用where、预加载with等ORM能力。

直接定义跨三层的标准Eloquent关联即可,不需要安装额外扩展,返回的是原生HasManyThrough实例,和你写的participants()关联用法完全一致:

// Event模型内
public function users(): \Illuminate\Database\Eloquent\Relations\HasManyThrough
{
    return $this->hasManyThrough(
        User::class,
        Participant::class,
        'booking_id',
        'user_id',
        'event_id',
        'participant_id'
    )->join('bookings', function ($join) {
        $join->on('bookings.booking_id', '=', 'participants.booking_id')
            ->where('bookings.event_id', $this->getKey());
    })->distinct();
}

补充说明

  1. 关联逻辑完全匹配你的表结构:活动关联报名单,报名单关联参与人记录,参与人记录关联对应用户。加distinct()是为了避免同一用户重复报名同一活动时返回重复用户数据,业务上如果限制单活动单用户只能报一次可以去掉这个调用。
  2. 这个写法返回的是标准Eloquent关系,支持所有链式查询操作:你可以正常调用where、orderBy、paginate、with等方法,预加载、模型绑定等原生ORM功能也都能正常工作。
  3. 顺便提一句,你现有的participants()关联参数写得有问题,第五个参数是当前Event模型的主键,应该填event_id而不是participant_id,之前能正常运行是巧合,建议修正:
    public function participants(): \Illuminate\Database\Eloquent\Relations\HasManyThrough
    {
        return $this->hasManyThrough(
            Participant::class,
            Booking::class,
            'event_id', // bookings表关联events的外键
            'booking_id', // participants表关联bookings的外键
            'event_id', // events表主键
            'booking_id' // bookings表主键
        );
    }
    

不要尝试手动构建集合返回,集合本身不具备关系类的查询构造能力,只要返回的不是继承自Relation的实例,就没法保留完整的Eloquent特性。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.30 13:33:15