多对多关系通过中间表实现,使用belongsToMany方法定义关联,支持自定义表名、外键、附加分离数据、同步角色及操作中间表额外字段。

在Laravel中,多对多关系是通过中间表(也叫枢纽表或连接表)来实现的。比如用户(User)和角色(Role)之间,一个用户可以拥有多个角色,一个角色也可以被多个用户拥有。这种情况下就需要使用Eloquent的“多对多”关联。
定义多对多关联
在Eloquent模型中,使用 belongsToMany 方法来定义多对多关系。
例如,我们有两个模型:User 和 Role,中间表为 role_user(默认按字母顺序组合):
User 模型:class User extends Model
{
public function roles()
{
return $this->belongsToMany(Role::class);
}
}
Role 模型:
class Role extends Model
{
public function users()
{
return $this->belongsToMany(User::class);
}
}
Laravel 默认会查找名为 role_user 的中间表(按相关模型名称的字母顺序)。如果你的中间表名称不同,比如是 user_roles,你需要在关联方法中指定:
return $this->belongsToMany(Role::class, 'user_roles');
自定义中间表字段名
如果中间表的外键不是默认的 user_id 和 role_id,你也可以手动指定:
return $this->belongsToMany(Role::class, 'user_roles', 'user_id', 'role_id');
- 第一个参数:关联模型类名
- 第二个参数:中间表名称
- 第三个参数:当前模型在中间表中的外键名
- 第四个参数:关联模型在中间表中的外键名
操作中间表数据(附加与分离)
使用 attach() 和 detach() 方法来管理多对多关系。
给用户分配角色:
$user = User::find(1); $user->roles()->attach(2); // 将角色ID为2的角色分配给用户
批量附加:
$user->roles()->attach([1, 3]); // 同时分配多个角色
移除角色:
$user->roles()->detach(2); // 移除单个角色 $user->roles()->detach([1,3]); // 移除多个角色 $user->roles()->detach(); // 移除所有角色
同步角色(保留指定ID):
$user->roles()->sync([1, 2, 3]); // 只保留角色1、2、3,其他全部移除
向中间表添加额外字段
如果中间表包含额外字段,比如 created_at 或自定义字段如 assigned_by,可以在 attach 时传入数组:
$user->roles()->attach(2, [
'assigned_by' => auth()->id(),
'created_at' => now()
]);
查询时若需访问这些字段,使用 pivot 属性:
foreach ($user->roles as $role) {
echo $role->pivot->assigned_by;
}
如果你想让 pivot 对象也能使用时间戳或访问其他模型属性,可以在定义关联时启用:
return $this->belongsToMany(Role::class)
->withPivot('assigned_by')
->withTimestamps();
条件筛选中间表字段
你可以基于中间表字段进行筛选:
// 查询被特定用户分配的角色
$user->roles()->wherePivot('assigned_by', 1)->get();
// 排序
$user->roles()->orderByPivot('created_at')->get();
基本上就这些。多对多关系在权限系统、标签系统等场景非常常见,掌握 belongsToMany、中间表操作和 pivot 的使用,能让你更高效地处理复杂数据关系。










