Laravel Eloquent多对多关联无法获取中间表district_id字段
解决Laravel 6.x多对多关联中间表额外字段及关联模型问题
1. 先获取中间表的district_id字段
在User和Role的多对多关联定义中,必须显式指定要携带的额外字段,使用withPivot方法:
User模型中的关联代码:
public function roles() { return $this->belongsToMany(Role::class) ->withPivot('district_id'); // 告诉框架要携带这个额外字段 }
若从Role反向查询User时也需要该字段,Role模型中同步添加:
public function users() { return $this->belongsToMany(User::class) ->withPivot('district_id'); }
现在调用User::with('roles')->get();后,就能通过$user->roles->first()->pivot->district_id获取到该字段的值。
2. 获取关联的District模型实例
如果想直接拿到District模型实例,最规范的做法是给中间表role_user定义Eloquent模型,通过嵌套关联加载:
第一步:创建RoleUser中间表模型
namespace App; use Illuminate\Database\Eloquent\Model; class RoleUser extends Model { protected $table = 'role_user'; // 指定对应中间表名 public $timestamps = false; // 中间表一般无时间戳字段,关闭该设置 // 关联District模型 public function district() { return $this->belongsTo(District::class); } // 关联Role模型,方便后续获取对应角色 public function role() { return $this->belongsTo(Role::class); } }
第二步:在User模型中添加中间表的关联
public function roleUsers() { return $this->hasMany(RoleUser::class); }
第三步:预加载关联数据
查询时直接嵌套预加载关联:
$users = User::with('roleUsers.district', 'roleUsers.role')->get();
之后就能通过$user->roleUsers->first()->district拿到District实例,同时$user->roleUsers->first()->role可获取对应的Role。
如果不想修改原有roles关联的用法,也可以用访问器实现,但要注意N+1查询性能问题:
在User模型中添加访问器:
public function getRolesWithDistrictAttribute() { return $this->roles->map(function ($role) { $role->setAttribute('district', District::find($role->pivot->district_id)); return $role; }); }
这种方式每处理一个角色就会发起一次District查询,数据量大时性能损耗明显,优先推荐中间表模型的预加载方案。
内容的提问来源于stack exchange,提问作者brandkast
相关产品推荐
相关产品推荐

