如何让Laravel识别外键相同但中间表type字段不同的多个多对多关联
问题根因
- 你传入
sync方法的参数本身存在语法问题:PHP数组不允许重复键名,你用同一个B::find(1)->id作为数组键,后面的['type'=>2]会直接覆盖前面的['type'=>1],实际传入sync的参数只有一条关联记录。 - Laravel默认的
belongsToMany多对多关联,是通过两个关联外键(这里是a_id和b_id)作为唯一识别标记,即使中间表有type字段,sync方法也会把相同b_id的关联视为同一条,只会保留最后传入的记录,自然无法插入两条相同外键、不同type的关联。
解决方案
方案1:直接用attach批量插入(适合不需要同步删除旧关联的场景)
attach方法支持传入多维数组批量插入关联,不需要用关联ID作为数组键,不会出现同键覆盖问题:
A::find(1)->bs()->attach([ ['b_id' => 1, 'type' => 1], ['b_id' => 1, 'type' => 2] ]);
执行后A::find(1)->bs()->where('id', 1)->count()就会返回2。
方案2:自定义逻辑模拟sync效果(需要同步删除旧关联的场景)
如果你需要和sync一样先清空当前模型的旧关联再插入新关联,可以自己写清库+批量插入的逻辑:
// 先删除当前A记录的所有旧关联 DB::table('a_b')->where('a_id', 1)->delete(); // 批量插入新关联 DB::table('a_b')->insert([ ['a_id' => 1, 'b_id' => 1, 'type' => 1], ['a_id' => 1, 'b_id' => 1, 'type' => 2] ]);
方案3:按type拆分关联(需要针对不同type单独做关联操作的场景)
如果不同type的关联业务逻辑独立,可以在模型中按type拆分多个关联,各自的sync操作互不影响:
class A extends Model { // type=1的关联 public function bsType1() { return $this->belongsToMany(B::class) ->withPivot(['type']) ->wherePivot('type', 1); } // type=2的关联 public function bsType2() { return $this->belongsToMany(B::class) ->withPivot(['type']) ->wherePivot('type', 2); } } // 单独同步type=1的关联 A::find(1)->bsType1()->sync([1]); // 单独同步type=2的关联 A::find(1)->bsType2()->sync([1]);
内容的提问来源于stack exchange,提问作者unnoq
相关产品推荐
相关产品推荐

