Gorm在关联中创建重复项

I have the following 2 structs with a many-2-many relationship.

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"`
}

If I create a Message with DB.Create(my_message), everything works fine : the Message is created in DB, along with a Location and the join message_locations table is filled with the respective IDs of the Message and the Location.

What I was expecting though was that if the Location already exists in DB (based on the place_id field, which is passed on), gorm would create the Message, retrieve the Location ID and populate message_locations.That's not what is happening. Since the PlaceID must be unique, gorm finds that a duplicate key value violates unique constraint "locations_place_id_key" and aborts the transaction.

If on the other hand I make the PlaceID not unique, gorm creates the message alright, with the association, but then that creates another, duplicate entry for the Location.

I can test if the location already exists before trying to save the message:

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

then if true switch the association off:

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

The message is saved without gorm complaining, but then message_locations is not filled. I could fill it "manually" since I've retrieved the Location ID when testing for its existence, but it seems to me it kind of defeats the purpose of using gorm in the first place.

I'm not sure what the right way to proceed might be. I might be missing something obvious, I suspect maybe something's wrong with the way I declared my structs? Hints welcome.

UPDATE 2016/03/25

I ended up doing the following, which I'm pretty sure is not optimal. If you have a better idea, please chime in.

After testing if the location already exists and it does:

// 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()

gorm:"many2many:message_locations;save_association:false"

Is getting closer to what you would like to have. You need to place it in your struct definition for Message. The field is then assumed to exist in the db and only the associations table will be populated with data.