Ich habe die folgenden 2 Strukturen mit einer Viele-2-Viele-Beziehung.Gorm erstellt doppelte Verknüpfung
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"`
}
Wenn ich eine Nachricht mit DB.Create (my_message) erstellen, funktioniert alles einwandfrei: die Nachricht in DB erstellt wird, zusammen mit einem Ort und die message_locations Join-Tabelle mit dem jeweiligen IDs der Nachricht gefüllt ist und der Standort.
Ich erwartete zwar, dass, wenn der Standort bereits in der Datenbank existiert (basierend auf dem Feld place_id, das übergeben wird), würde Gorm die Nachricht erstellen, die Standort-ID abrufen und message_locations füllen. Das ist nicht was passiert . Da die PlaceID eindeutig sein muss, findet gorm, dass ein doppelter Schlüsselwert die eindeutige Integritätsbedingung "locations_place_id_key" verletzt und die Transaktion abbricht.
Wenn andererseits die PlaceID nicht eindeutig ist, erstellt gorm die Nachricht in Ordnung, mit der Zuordnung, aber das erstellt dann einen anderen, doppelten Eintrag für den Standort.
Ich kann testen, ob der Standort bereits vorhanden ist, bevor Sie versuchen, die Nachricht zu speichern:
existsLoc := Location{}
DB.Where("place_id = ?", mssg.Locations[0].PlaceID).First(&existsLoc)
dann, wenn wahr Schalter der Verband aus:
DB.Set("gorm:save_associations", false).Create(mssg)
DB.Create(mssg)
Die Nachricht gespeichert wird, ohne gorm beschweren, aber dann ist message_locations nicht gefüllt. Ich könnte es "manuell" ausfüllen, da ich die Standort-ID beim Testen auf seine Existenz abgerufen habe, aber es scheint mir, dass es den Zweck der Verwendung von Gorm in erster Linie vereitelt.
Ich bin mir nicht sicher, was der richtige Weg zu gehen könnte. Ich könnte etwas Offensichtliches vermissen, ich vermute, vielleicht stimmt etwas nicht mit der Art und Weise, wie ich meine Strukturen deklariert habe? Hinweise willkommen.
UPDATE 2016/03/25
landete ich Sie folgendermaßen vorgehen, den ich bin ziemlich sicher nicht optimal ist. Wenn Sie eine bessere Idee haben, bitte läuten
Nach der Prüfung, ob bereits der Standort existiert, und es tut.
// 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()
Ja, ich dachte darüber nach. Statt 'DB.Set (" gorm: save_associations ", false)' von Fall zu Fall. Aber es scheint, als wäre es ein halb volles Glas statt halb leer. Denn dann nimmt Gorm immer wieder an, dass das Feld existiert, aber ich kann mich nicht darauf verlassen. Jemand anderes hat ein [Problem auf dem gorm Repo] (https://github.com/jinzhu/gorm/issues/1061) dafür gemacht. Es ist offen. – nicomo