如何在Gorm保存时忽略多对多关系中的关联实体
问题:GORM保存多对多关联时重复插入关联实体并触发钩子
使用GORM连接MySQL时,存在User和Language的多对多关系,保存User实体时,GORM会尝试插入已存在的Language实体并触发其afterCreate钩子,不符合预期。
模型定义
type Language struct { gorm.Model Name string } type User struct { gorm.Model Name string Languages []Language `gorm:"many2many:user_languages;"` }
触发问题的代码
var languages []Language err := db.Find(&languages).Error if err != nil { panic(err) } user := User{Name: "dexter", Languages: languages} err = db.Save(&user).Error if err != nil { panic(err) }
生成的冗余SQL
INSERT INTO `languages` (`created_at`,`updated_at`,`deleted_at`,`name`,`id`) VALUES ('2024-01-22 19:44:37.247','2024-01-22 19:44:37.247','eng',55),('2024-01-22 19:44:37.247','2024-01-22 19:44:37.247','hin',57) ON DUPLICATE KEY UPDATE `id`=`id`
需求:完全避免插入Language表,跳过afterCreate钩子。
解决方案
方法1:通过关联模式(Association Mode)建立关联
先单独保存User实体,再通过GORM的关联API添加已有的Language关联,此方式仅操作中间表user_languages,不会修改Language表:
// 1. 先保存用户,不处理关联 user := User{Name: "dexter"} err = db.Create(&user).Error if err != nil { panic(err) } // 2. 通过关联模式添加已有的语言,仅创建中间表关联 err = db.Model(&user).Association("Languages").Append(languages) if err != nil { panic(err) }
方法2:修改关联标签,禁用自动创建/更新关联实体
在User模型的Languages字段标签中添加association_autocreate:false和association_autoupdate:false,告诉GORM不要自动创建或更新关联的Language实体,仅处理中间表关联:
type User struct { gorm.Model Name string Languages []Language `gorm:"many2many:user_languages;association_autocreate:false;association_autoupdate:false;"` }
之后执行原代码的Save操作,GORM只会创建User与Language之间的中间表关联,不会对Language表执行任何插入/更新操作,自然也不会触发afterCreate钩子。
注意:使用此方法时,需确保
languages中的实体已存在于数据库且包含有效的ID字段,GORM需要通过ID创建中间表关联记录。
内容的提问来源于stack exchange,提问作者amar1104
相关产品推荐
相关产品推荐

