在枢轴模型上对关系进行预加载

后端开发 2026-07-09

是否有办法在预加载中加载在中间模型中定义的关联,以避免N+1查询?

经过查阅文档和大量文章,我得到了以下4 个模型:

  • Student
  • Assessment
  • StudentAssessment(M-N中间表)
  • AssessmentResult(与StudentAssessment的一对一关系)

每个模型的关系:

  • Student => assessments(): BelongsToMany
  • Assessment => students(): BelongsToMany
  • StudentAssessment => student(): BelongsTo, assessments(): BelongsTo, assessment_result(): HasOne
  • AssessmentResult: student_assessment(): BelongsTo

StudentAssessment与 AssessmentResult都继承自Pivot而不是Model。students 关系在 Assessment 模型上也明确使用 withPivotusing:

  public function students(): BelongsToMany  
  {  
    return $this->belongsToMany(  
      Student::class,  
      'student_assessments',  
      'assessment_id',  
      'student_id'     
    )->using(StudentAssessment::class)  
      ->withPivot('id');  
  }

我仍然无法实现 $assessment->students()->with('pivot.assessment_result')。在预加载路径中,Laravel对中间表关系并不友好。

当然,我可以使用 foreach > load() 的模式逐个加载结果。只是我想避免那样做。

解决方案

你可以通过将pivot转换为自定义pivot模型来实现—

class StudentAssessment extends Pivot
{
    protected $table = 'student_assessment';

    public function assessment_result()
    {
        return $this->hasOne(AssessmentResult::class, 'student_assessment_id');
    }
}

在Assessment模型上定义关系 -

class Assessment extends Model
{
    public function students()
    {
        return $this->belongsToMany(Student::class)
            ->using(StudentAssessment::class)
            ->withPivot(['id']);
    }
}

现在你可以在pivot模型上定义关系,这些关系在通过父关系对pivot模型进行水合后就可用 -

$assessments = Assessment::with('students')->get();

用法 -

foreach ($assessments as $assessment) {
    foreach ($assessment->students as $student) {
        $result = $student->pivot->assessment_result;
    }
}
站内所有文章版权归属LeftHeroAI导航站,无授权禁止任何主体转载、抄袭、复制内容,亦不得私自架设镜像站点。一经侵权,本站将通过法律途径追责。

相关文章