首页 文章

Gorm创建了重复的副本

提问于
浏览
2

我有以下2个结构,有很多2对多的关系 .

type Message struct {
    gorm.Model
    Body         string     `tag:"body" schema:"body"`
    Locations    []Location `tag:"locations" gorm:"many2many:message_locations;"`
    TimeSent     time.Time  `tag:"timesent"`
    TimeReceived time.Time  `tag:"timereceived"`
    User         User
}

type Location struct {
    gorm.Model
    PlaceID string  `tag:"loc_id" gorm:"unique"`
    Lat     float64 `tag:"loc_lat"`
    Lng     float64 `tag:"loc_lng"`
}

如果我使用DB.Create(my_message)创建一个消息,一切正常:消息在DB中创建,连同一个Location,并且join message_locations表填充了Message和Location的相应ID .

我期待的是,如果位置已经存在于DB中(基于传入的place_id字段),gorm将创建Message,检索Location ID并填充message_locations . 这不是正在发生的事情 . 由于PlaceID必须是唯一的,因此gorm会发现重复的键值违反了唯一约束“locations_place_id_key”并中止了该事务 .

另一方面,如果我使PlaceID不唯一,gorm会使用关联创建消息,但随后会为Location创建另一个重复条目 .

在尝试保存邮件之前,我可以测试该位置是否已存在:

existsLoc := Location{}
DB.Where("place_id = ?", mssg.Locations[0].PlaceID).First(&existsLoc)

然后如果为true则关闭关联:

DB.Set("gorm:save_associations", false).Create(mssg)
DB.Create(mssg)

保存的消息没有gorm抱怨,但是没有填充message_locations . 我可以“手动”填写它,因为我在测试它的存在时检索了位置ID,但在我看来,它首先打败了使用gorm的目的 .

我不确定正确的方法是什么 . 我可能会遗漏一些明显的东西,我怀疑我宣布结构的方式可能有些不对劲?提示欢迎 .

UPDATE 2016/03/25

我最终做了以下,我很确定这不是最佳的 . 如果你有更好的主意,请加入 .

在测试该位置是否已经存在之后它确实:

// in a transaction
tx := DB.Begin()

// create the message with transaction disabled
if errMssgCreate := tx.Set("gorm:save_associations", false).Create(mssg).Error; errMssgCreate != nil {
            tx.Rollback()
            log.Println(errMssgCreate)
}

// then create the association with existing location
if errMssgLocCreate := tx.Model(&mssg).Association("Locations").Replace(&existLoc).Error; errMssgLocCreate != nil {
            tx.Rollback()
            log.Println(errMssgLocCreate)
}

tx.Commit()

1 回答

  • 0

    gorm:"many2many:message_locations;save_association:false"

    越来越接近你想拥有的东西了 . 您需要将它放在Message的结构定义中 . 然后假定该字段存在于db中,并且只有关联表将填充数据 .

相关问题