From 02f6ae3c4ed211472b0492cee02ff3ddfdc1830d Mon Sep 17 00:00:00 2001 From: Jinzhu Date: Wed, 7 Sep 2016 21:54:19 +0800 Subject: [PATCH] If failed to update current record with Save, try to create a new one --- main.go | 10 +++++++--- main_test.go | 10 ++++++++-- 2 files changed, 15 insertions(+), 5 deletions(-) diff --git a/main.go b/main.go index 04f39228..bce3c56b 100644 --- a/main.go +++ b/main.go @@ -363,10 +363,14 @@ func (s *DB) UpdateColumns(values interface{}) *DB { // Save update value in database, if the value doesn't have primary key, will insert it func (s *DB) Save(value interface{}) *DB { scope := s.clone().NewScope(value) - if scope.PrimaryKeyZero() { - return scope.callCallbacks(s.parent.callbacks.creates).db + if !scope.PrimaryKeyZero() { + newDB := scope.callCallbacks(s.parent.callbacks.updates).db + if newDB.Error == nil && newDB.RowsAffected == 0 { + return s.New().FirstOrCreate(value) + } + return newDB } - return scope.callCallbacks(s.parent.callbacks.updates).db + return scope.callCallbacks(s.parent.callbacks.creates).db } // Create insert the value into database diff --git a/main_test.go b/main_test.go index 1344c65b..0e129dde 100644 --- a/main_test.go +++ b/main_test.go @@ -81,10 +81,16 @@ func TestStringPrimaryKey(t *testing.T) { ID string `gorm:"primary_key"` Name string } + DB.DropTable(&UUIDStruct{}) DB.AutoMigrate(&UUIDStruct{}) data := UUIDStruct{ID: "uuid", Name: "hello"} - if err := DB.Save(&data).Error; err != nil || data.ID != "uuid" { + if err := DB.Save(&data).Error; err != nil || data.ID != "uuid" || data.Name != "hello" { + t.Errorf("string primary key should not be populated") + } + + data = UUIDStruct{ID: "uuid", Name: "hello world"} + if err := DB.Save(&data).Error; err != nil || data.ID != "uuid" || data.Name != "hello world" { t.Errorf("string primary key should not be populated") } } @@ -541,7 +547,7 @@ func TestJoins(t *testing.T) { } var users5 []User - db5 := DB.Joins("join emails on emails.user_id = users.id AND emails.email = ?", "join1@example.com").Joins("join credit_cards on credit_cards.user_id = users.id AND credit_cards.number = ?", "411111111111").Where(User{Id:1}).Where(Email{Id:1}).Not(Email{Id:10}).First(&users5) + db5 := DB.Joins("join emails on emails.user_id = users.id AND emails.email = ?", "join1@example.com").Joins("join credit_cards on credit_cards.user_id = users.id AND credit_cards.number = ?", "411111111111").Where(User{Id: 1}).Where(Email{Id: 1}).Not(Email{Id: 10}).First(&users5) if db5.Error != nil { t.Errorf("Should not raise error for join where identical fields in different tables. Error: %s", db5.Error.Error()) }