Laravel观察者向中间表添加行后随即删除的问题排查与解决
问题:Laravel多对多关联中间表数据自动删除的排查与解决
场景说明
我在Laravel中通过role_user_table中间表实现User和Role模型的多对多关联,遇到了一个异常情况:观察者向中间表添加数据后,这些数据会被自动删除。日志和中间表自增字段的变化都能佐证这一点,哪怕用dd()输出syncWithoutDetaching的返回结果是正确的,数据依然留不住。
相关代码
User模型代码
public static function boot(): void { parent::boot(); self::observe(new UserObserver()); } public function roles(): belongsToMany { return $this->belongsToMany( Role::class, 'role_user_table', 'user_id', 'role_id' )->using(RoleUser::class); }
RoleUser中间表模型代码
class RoleUser extends Pivot { use CrudTrait; use HasFactory; protected $table = 'role_user_table'; public $incrementing = true; protected $fillable = [ 'id', 'user_id', 'role_id', ]; }
UserObserver观察者代码
public function saved(User $model): void { $this->model = $model; if ($this->model->all_roles) { $roles= Role::pluck('id')->toArray(); $this->model->roles()->syncWithoutDetaching($roles); } }
排查与解决过程
我使用的是Backpack CRUD,排查时发现观察者本身逻辑正常,用任何同步方法(sync/attach/detach等)都能正常添加记录,但后续数据会被自动删除。
一开始尝试把同步逻辑放到setupCreateOperation中,结果和用观察者的情况完全一致——数据添加后被删除:
public function setupCreateOperation() { User::saved(function($entry) { $roles= Role::pluck('id')->toArray(); $entry->roles()->syncWithoutDetaching($roles); }); }
之后我将同步代码移到store和update方法内,放在默认的traitStore()和traitUpdate()执行之后,数据就能正常保留了。推测是Backpack的CRUD trait会维护数据状态,在其执行前修改关联数据会触发回滚操作。修改后的代码如下:
public function store() { $response = $this->traitStore(); // 保存后执行角色同步 $this->syncRoles($this->data['entry']->id, $this->data['entry']->all_roles); return $response; } public function update(UserRequest $request) { $response = $this->traitUpdate(); // 更新后执行角色同步 $this->syncRoles($request['id'], $request['all_roles']); return $response; } public function syncRoles(int $id, int $all_roles): void { if ($all_roles) { $roles = Role::pluck('id')->toArray(); User::find($id)->roles()->syncWithoutDetaching($roles); } }
注:修正了原代码中的笔误:
udate改为update,role()改为roles()
内容的提问来源于stack exchange,提问作者KordDEM
相关产品推荐
相关产品推荐

