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

Laravel关联查询问题:通过whereHas筛选指定院校的Enrolment

排查whereHas问题并实现需求功能

首先,咱们来拆解你遇到的问题:你的whereHas使用问题主要出在两个地方——关联查询的字段名错误,以及可能的hasOneThrough关联定义不准确。另外,你当前的代码只做了查询,没有处理“未找到则创建Enrolment”的逻辑,我会帮你把完整流程补全。

1. 修正whereHas的查询逻辑

你的Enrolment(StudentBursaryEnrolment)模型通过hasOneThrough关联到AcademicInstitution,但你在whereHas里用了where('academic_institution','=','Pearson Institute'),这明显不对——AcademicInstitution表的名称字段应该是类似name的字段(而不是academic_institution),而且因为关联是通过Campus(AcademicInstitutionCampus)间接关联的,我们可以有两种写法:

写法一:直接通过academic_institution关联查询

如果你的hasOneThrough关联定义正确,直接用whereHas关联academic_institution即可,但要修正字段名:

$student = Student::findOrFail(1);
$bursary = $student->bursaries()->first();

// 查询关联到Pearson Institute的Enrolment
$enrolment = $bursary->enrolments()
    ->whereHas('academic_institution', function ($query) {
        // 这里替换成你AcademicInstitution表中存储名称的字段,比如name
        $query->where('name', 'Pearson Institute');
    })
    ->first(); // 用first()而不是get(),因为我们只需要单个匹配的记录

写法二:通过中间表Campus间接查询(更直观)

如果你对hasOneThrough的关联没把握,可以直接通过academic_institution_campus关联嵌套查询,这样逻辑更清晰:

$enrolment = $bursary->enrolments()
    ->whereHas('academic_institution_campus', function ($query) {
        $query->whereHas('academic_institution', function ($subQuery) {
            $subQuery->where('name', 'Pearson Institute');
        });
    })
    ->first();

2. 检查并修正hasOneThrough关联定义

你的StudentBursaryEnrolment模型中的academic_institution关联可能参数顺序有误,hasOneThrough的参数需要严格对应表之间的外键关系,正确的定义应该是:

public function academic_institution() {
    return $this->hasOneThrough(
        \App\AcademicInstitution::class,
        \App\AcademicInstitutionCampus::class,
        'id', // 中间表(AcademicInstitutionCampus)的主键,对应Enrolment的academic_institution_campus_id
        'id', // 目标表(AcademicInstitution)的主键
        'academic_institution_campus_id', // Enrolment表中关联到Campus的外键
        'academic_institution_id' // Campus表中关联到AcademicInstitution的外键
    );
}

如果这个关联定义错误,whereHas会无法正确关联到AcademicInstitution表。

3. 完整实现:查询或创建Enrolment并添加课程

接下来补全“未找到则创建Enrolment”的逻辑,同时创建课程:

$student = Student::findOrFail(1);
$bursary = $student->bursaries()->first();

// 1. 查询目标Enrolment
$enrolment = $bursary->enrolments()
    ->whereHas('academic_institution_campus', function ($query) {
        $query->whereHas('academic_institution', function ($subQuery) {
            $subQuery->where('name', 'Pearson Institute');
        });
    })
    ->first();

// 2. 如果未找到,创建对应的Enrolment
if (!$enrolment) {
    // 先找到Pearson Institute对应的AcademicInstitution和它的一个Campus
    $academicInstitution = \App\AcademicInstitution::where('name', 'Pearson Institute')->firstOrFail();
    $campus = $academicInstitution->campuses()->firstOrFail(); // 假设AcademicInstitution有hasMany campuses的关联

    // 创建Enrolment
    $enrolment = $bursary->enrolments()->create([
        'academic_institution_campus_id' => $campus->id,
        'student_number' => $student->student_number, // 替换成你的Student表中对应的学号字段
        // 其他必填字段请根据你的模型fillable补充
    ]);
}

// 3. 在找到/创建的Enrolment下创建课程
$enrolment->courses()->create([
    // 替换成你的Course模型需要的字段,比如:
    // 'course_name' => 'Math 101',
    // 'course_code' => 'MATH101'
]);

关键注意点

  • 确保AcademicInstitution模型和AcademicInstitutionCampus模型之间有正确的关联(比如AcademicInstitution有hasMany campuses的关联)。
  • 替换代码中所有占位的字段名(比如name、student_number)为你数据库中实际的字段名。
  • 使用first()而不是get(),因为我们只需要单个匹配的Enrolment记录。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.05.14 06:49:12