Laravel中如何在ClassMeet模型定义多层关联获取Subject表科目名称
实现方案
你的三张表关联逻辑为:class_meets.routine_id → routines.id、routines.subject_id → subjects.id,以下两种方案都可以实现从ClassMeet出发查询关联Subject的需求:
方式1:嵌套关联(最常用,维护成本低)
先补全各模型的基础关联定义即可:
第一步:给Routine模型新增关联Subject的方法
class Routine extends Model { use SoftDeletes; public $table = 'routines'; protected $dates = ['created_at', 'updated_at', 'deleted_at']; protected $fillable = [ 'academic_year_id', 'subject_id', 'classes_id', // 注意:你现有代码这里少了逗号,会触发语法错误,记得补上 'day', 'start_time', 'end_time', ]; // 新增关联 public function subject() { return $this->belongsTo(Subject::class); } }
第二步:给ClassMeet模型新增关联Routine的方法
class ClassMeet extends Model { use SoftDeletes; public $table = 'class_meets'; protected $dates = ['created_at', 'updated_at', 'deleted_at', 'date']; protected $fillable = [ 'routine_id', 'date' ]; // 新增关联 public function routine() { return $this->belongsTo(Routine::class); } }
使用方法
查询时用嵌套预加载即可直接获取科目名称:
// 查询所有ClassMeet及关联的科目信息 $classMeets = ClassMeet::with('routine.subject')->get(); // 取值示例 foreach ($classMeets as $meet) { echo $meet->date; // class_meets自身字段 echo $meet->routine->subject->subject_name; // 关联拿到的科目名称 }
方式2:直接定义hasOneThrough关联(无需嵌套调用)
如果不想每次都通过routine嵌套获取科目,可以直接在ClassMeet中定义跨表关联:
class ClassMeet extends Model { use SoftDeletes; public $table = 'class_meets'; protected $dates = ['created_at', 'updated_at', 'deleted_at', 'date']; protected $fillable = [ 'routine_id', 'date' ]; // 基础关联还是需要保留 public function routine() { return $this->belongsTo(Routine::class); } // 新增直达Subject的关联 public function subject() { return $this->hasOneThrough( Subject::class, // 最终要获取的目标模型 Routine::class, // 中间模型 'id', // 中间表routines的主键 'id', // 目标表subjects的主键 'routine_id', // 当前表class_meets关联中间表的外键 'subject_id' // 中间表routines关联目标表的外键 ); } }
使用方法
直接预加载subject关联即可:
$classMeets = ClassMeet::with('subject')->get(); // 直接取值 foreach ($classMeets as $meet) { echo $meet->date; echo $meet->subject->subject_name; }
软删除适配说明
如果需要查询包含已软删除的Routine或Subject数据,在关联定义末尾加上->withTrashed()即可,示例:
// 关联时包含已软删除的Routine return $this->belongsTo(Routine::class)->withTrashed();
内容的提问来源于stack exchange,提问作者Agus
相关产品推荐
相关产品推荐

