You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.07 12:35:18