Laravel 5.8中如何获取单条记录对应的关联模型数据
问题场景
现有三张数据表,关联关系如下:
months表与registration表为一对多(one-to-many)关系years表与registration表为一对多(one-to-many)关系
表结构与模型定义
registrations表迁移代码
public function up() { Schema::create('registrations', function (Blueprint $table) { $table->bigIncrements('id'); $table->string('name'); $table->string('father_name'); $table->string('contact1'); $table->string('contact2')->nullable(); $table->string('address')->nullable(); $table->integer('amount'); $table->integer('day'); $table->unsignedInteger('month_id'); $table->unsignedBigInteger('year_id'); $table->timestamps(); }); }
Registration模型代码
class Registration extends Model { protected $fillable = ['name', 'father_name', 'contact1', 'contact2', 'address', 'amount', 'day', 'month_id', 'year_id' ]; public function month() { return $this->belongsTo(Month::class); } public function year() { return $this->belongsTo(Year::class); } }
Month模型代码
class Month extends Model { public function registration() { return $this->hasMany(Registration::class); } }
Year模型代码
class Year extends Model { public function registration() { return $this->hasMany(Registration::class); } }
问题描述
需求为查询单条registration记录及其关联的month、year数据,控制器show方法原有代码如下:
public function show(Registration $reg) { $registration = $reg::with('month', 'year')->get(); return ['registration' => $registration]; }
执行上述代码后返回了全量registration记录,而非路由模型绑定注入的目标单条记录。测试发现直接通过模型名调用with方法可以正确获取带关联的全量记录,但对注入的单条模型实例使用with方法仍返回全量数据,不符合预期,需要实现仅获取当前单条registration实例关联的Month和Year数据的效果。
问题原因
返回全量数据的核心原因是:$reg::with(...)属于静态调用模型类的查询构造器方法,等价于直接写Registration::with(...),和传入的$reg实例没有任何关联,后续调用get()自然会查询全表返回所有记录。
解决方案
有两种常用实现方式,按需选择即可:
方案1:对已注入的模型实例加载关联(推荐)
路由模型绑定已经查询出单条$reg实例,此时不需要重新发起全表查询,直接调用load()方法加载当前实例的关联数据即可:
public function show(Registration $reg) { // 加载当前实例关联的month和year数据 $reg->load('month', 'year'); return ['registration' => $reg]; }
load()是针对已存在的模型实例做懒惰预加载,只会加载当前这条记录对应的关联数据,不会额外查询全表,性能更优。
方案2:通过实例ID发起单条带关联的查询
如果需要重新走查询构造器获取带关联的单条记录,可以用传入实例的id做条件约束,调用find()获取单条结果:
public function show(Registration $reg) { $registration = Registration::with('month', 'year')->find($reg->id); return ['registration' => $registration]; }
注意:该方式会多执行一次数据库查询,性能弱于方案1,非特殊场景优先选择方案1。
内容的提问来源于stack exchange,提问作者Abdul Raheem Ghani
相关产品推荐
相关产品推荐

