Laravel多表共用中间表belongsToMany关联误删数据问题
问题根源分析
1. 多对多关联删除方法使用错误
你在多对多关联上直接调用delete()方法,会直接删除目标主表(title_set、image_set)的对应数据,而非仅删除中间表creative_set的关联记录。如果你只是想解除创意和对应标题集、图片集的关联,正确方法是调用多对多关联的detach()方法,该方法只会清除中间表的对应关联记录,不会影响主表数据。
2. 复用同一张中间表存储两类关联无类型区分
你使用同一张creative_set中间表同时存储creative和title_set、creative和image_set的关联,中间表没有字段标识set_id对应的是title_set的id还是image_set的id,导致查询关联时会拉取当前创意在中间表的所有set_id,不管它属于哪类关联:
- 比如创意A关联的Title Set 01的id是1,中间表存入
creative_id=A_id, set_id=1 - 当你调用创意A的
$this->imageSets()->delete()时,Laravel会先从中间表取出所有creative_id=A_id的set_id(也就是1),然后去image_set表删除id=1的记录 - 如果此时创意B关联的Image Set 01的id刚好是1,就会被误删,这就是为什么创意B的关联会受影响。
3. 删除逻辑顺序错误
你先删除了主表的标题、图片记录,再删除中间表记录,逻辑顺序也不合理。
修复方案
方案1:拆分中间表(推荐)
为两类关联分别创建独立的中间表,避免类型冲突:
- 创建
creative_title_set中间表,存储创意和标题集的关联 - 创建
creative_image_set中间表,存储创意和图片集的关联
重新配置关联后,删除关联的方法修改为:
public function deleteRelations() { // detach只会删除中间表的关联记录,不会删除title_set、image_set的主表数据 $this->titleSets()->detach(); $this->imageSets()->detach(); }
方案2:在原有中间表增加类型字段
如果不想拆分表,可以给creative_set增加set_type字段,标识当前set_id对应的模型类型,关联配置时加上条件:
public function imageSets() { return $this->belongsToMany('App\Models\ImageSet', 'creative_set', 'creative_id', 'set_id') ->wherePivot('set_type', ImageSet::class); } public function titleSets() { return $this->belongsToMany('App\Models\TitleSet', 'creative_set', 'creative_id', 'set_id') ->wherePivot('set_type', TitleSet::class); }
新增关联时需要同步写入set_type的值,删除关联同样使用detach()即可。
内容的提问来源于stack exchange,提问作者Son Le
相关产品推荐
相关产品推荐

