如何通过一层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(); }
补充说明
- 关联逻辑完全匹配你的表结构:活动关联报名单,报名单关联参与人记录,参与人记录关联对应用户。加
distinct()是为了避免同一用户重复报名同一活动时返回重复用户数据,业务上如果限制单活动单用户只能报一次可以去掉这个调用。 - 这个写法返回的是标准Eloquent关系,支持所有链式查询操作:你可以正常调用
where、orderBy、paginate、with等方法,预加载、模型绑定等原生ORM功能也都能正常工作。 - 顺便提一句,你现有的
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
相关产品推荐
相关产品推荐

