Laravel中hasOneThrough关联返回首行而非关联行的问题
Laravel 关联查询异常:Grade 关联返回数据表首行而非对应数据
数据表结构
grades表
id | grade 1 | 1 2 | 2
services表
id | service 1 | service1 2 | service2
comments表
id | comment 1 | comment1 2 | comment2 3 | comment3
comments_services中间表
id | service_id | grade_id(nullable) | comment_id 1 | 1 | null | 1 2 | 1 | 2 | 2 3 | 2 | 3 | 3
当前关联代码
Comment 模型的 services 关联
public function services(){ return $this->belongsToMany(Service::class, 'comments_services', 'comment_id', 'service_id', 'id') ->with('grade'); }
Service 模型的 grade 关联
public function grade(){ return $this->hasOneThrough(Grade::class, Service::class, 'service_id', 'id', 'id', 'grade_id'); }
问题现象
grade关联未返回对应评论的Grade数据,而是返回grades表的首行数据- 生成的查询语句:
select `grade_id`, `grade`, `comments_services`.`service_id` as `laravel_through_key` from `grades` inner join `comments_services` on `comments_services`.`grade_id` = `grades`.`id` where `comments_services`.`service_id` in (1, 2, 6, 10)
- 所有带Grade的评论返回的数据示例:
"grade" => array:3 [▼ "id" => 1 "grade" => "1" "laravel_through_key" => 2 ]
错误原因
Service模型中hasOneThrough的参数使用错误:
- 第二个参数错误传入了
Service::class,实际应该指定中间表comments_services对应的模型 - 关联逻辑未绑定到当前评论的
comment_id,导致仅通过service_id筛选时返回了匹配结果的首行
解决方案
方案1:使用中间表模型关联Grade(推荐)
- 创建中间表模型
CommentsServices:
namespace App\Models; use Illuminate\Database\Eloquent\Relations\Pivot; class CommentsServices extends Pivot { public function grade() { return $this->belongsTo(Grade::class); } }
- 修改Comment模型的services关联:
public function services() { return $this->belongsToMany(Service::class, 'comments_services', 'comment_id', 'service_id') ->using(CommentsServices::class) // 指定中间表模型 ->withPivot('grade_id') // 加载中间表的grade_id字段 ->with('pivot.grade'); // 加载中间表关联的Grade }
- 获取关联数据:
// 在控制器或视图中,通过pivot访问对应Grade foreach ($comment->services as $service) { $grade = $service->pivot->grade; // 得到当前评论-服务关联对应的Grade }
方案2:修正hasOneThrough参数(仅适用于单场景)
如果坚持使用hasOneThrough,需修正参数指定正确的中间表模型:
// Service模型的grade关联 public function grade() { return $this->hasOneThrough( Grade::class, \App\Models\CommentsServices::class, // 中间表模型 'service_id', // 中间表关联Service的外键 'id', // Grade表主键 'id', // Service表主键 'grade_id' // 中间表关联Grade的外键 ); }
注:此方案仍会返回该Service对应的第一条Grade记录,无法区分不同Comment的关联,仅适用于单个Service仅对应一个Grade的场景。
失败尝试说明
之前拆分关联的写法错误,因为Service模型的ser关联错误关联了自身,且未绑定到中间表的关联逻辑,导致无法正确获取对应Grade。
内容的提问来源于stack exchange,提问作者mmdev
相关产品推荐
相关产品推荐

