Gorm 多对多关系重复值

我正在尝试在我的演示API中,在 技能和技能列表之间设置多对多关系。Job[]Skill


作业结构


type Job struct {

    ID          string              `sql:"type:uuid;primary_key;"`

    Title       string              `json:"title,omitempty"`

    Skills      []*skill.Skill      `json:"skills,omitempty"gorm:"many2many:job_skill;"`

    CreatedAt   time.Time

    UpdatedAt   time.Time

}

技能结构


type Skill struct {

    gorm.Model

    Name string `json:"name,omitempty"`

}

然后,我使用 自动生成联接表。gorm.DB.AutoMigrate()


当我向我的 API 发送请求时,数据在第一次时就会正确创建,并且联接表会按预期方式填充。POST


示例数据POST


{

    "title": "Senior Python Engineer",      

    "skills": [{"name": "javascript"}, {"name": "python"}]

}

但是,当我发送添加新技能的请求时,它会复制技能表中的技能,然后在联接表中为已存在的技能创建新记录。PATCH


示例数据PATCH


{

    "title": "Lead Engineer",      

    "skills": [{"name": "javascript"}, {"name": "python"}, {"name": "management"}]

}

对数据执行 get 请求将显示以下内容:


{

    "title": "Lead Engineer",      

    "skills": [{"name": "javascript"}, {"name": "python"}, {"name": "javascript"}, {"name": "python"}, {"name": "management"}]

}

我也尝试过设置所击中的技能,但是当添加新技能时,它失败了,因为它说另外两个已经存在,这很好,但随后不会添加新的技能。gorm:"unique"Name


我假设我只能发回新值?不是整个列表?


为了清楚起见,我的一些Go代码


func GetJobs(w http.ResponseWriter, r *http.Request) {

    j := &[]Job{}

    o := database.DB.Preload("Skills").Find(&j)


    render.JSON(w, r, o)

}


func UpdateJob(w http.ResponseWriter, r *http.Request) {

    j := &Job{}

    err := json.NewDecoder(r.Body).Decode(j)

    if err != nil {

        return

    }

    o := database.DB.Model(&j).Where("id = ?", j.ID).Update(&j)


    render.JSON(w, r, o)

}


九州编程
浏览 208回答 2
2回答

眼眸繁星

这是Gorm联想的两件事,我觉得在其文档中没有充分传达,这继续让开发人员感到困惑。1) 它使用 ID 来标识关联的实体当您更新该技能列表时,如果它们中没有要添加的ID,则它们只是要添加的新实体。这会导致您的值重复。即使您有一个字段,如果该字段不是实体的主键,则 gorm 将尝试创建新记录并导致约束冲突。unique有几种方法可以解决这个问题:确保 API 用户必须为相关实体提供 ID通过用户提供的其他代理键从数据库中提取实体 ID,并将其填充到要保存的实体中。在你的情况下,这可能是因为它是独一无二的。name使该代理键成为主键(使结构成为)。namegorm:"primaryKey"Skill2) 更新时,它不会删除关联切片中未显示的现有关联调用 Save/Update gorm 时,不会删除集合关联远端的实体。这是一项安全功能,可避免在简单的保存/更新中意外删除数据。你必须明确地想要这种行为。要解决此问题,您可以使用关联模式替换集合,作为更新的一部分:。db.Model(&job).Association('Skills').Replace(&job.Skills)

繁花如伊

详细阐述Eziquel的答案,并展示什么对我有用。我更新了我的技能结构,将 用作主键Nametype Skill struct {    Name string `json:"name,omitempty" gorm:"primary_key"`}然后,我阅读了一些文档,只是使用不确定它的作用,但是没有它,关联就会复制或未更新。gorm.DB.Session(&gorm.Session{FullSaveAssociations: true}).Updates(&j)func UpdateJob(w http.ResponseWriter, r *http.Request) {    j := &Job{}    err := json.NewDecoder(r.Body).Decode(j)    if err != nil {        return    }    database.DB.Session(&gorm.Session{FullSaveAssociations: true}).Updates(&j)    database.DB.Model(&j).Association("Skills").Replace(&j.Skills)    render.JSON(w, r, &j)}我不知道该怎么办,但我看到Jihnzu说要在文档中使用它,没有进一步的解释。结合使用,请确保没有重复项,并且关联会更新。database.DB.Session(&gorm.Session{FullSaveAssociations: true}).Updates(&j).Association("Skills").Replace(&j.Skills)如果有多个,你会做的:database.DB.Session(&gorm.Session{FullSaveAssociations: true}).Updates(&j)database.DB.Model(&j).Association("Skills").Replace(&j.Skills)database.DB.Model(&j).Association("Locations").Replace(&j.Locations)
打开App,查看更多内容
随时随地看视频慕课网APP

相关分类

Go