Merge pull request #438 from jaytaylor/jay/update-columns-skip-associations

Skip saving associations during UpdateColumns(...)
This commit is contained in:
Jinzhu 2015-03-30 14:44:41 +08:00
commit 14620058ed
5 changed files with 45 additions and 1 deletions

View File

@ -360,7 +360,7 @@ db.Model(&user).Updates(User{Name: "hello", Age: 18})
### Update Without Callbacks ### Update Without Callbacks
By default, update will call BeforeUpdate, AfterUpdate callbacks, if you want to update w/o callbacks: By default, update will call BeforeUpdate, AfterUpdate callbacks, if you want to update w/o callbacks and w/o saving associations:
```go ```go
db.Model(&user).UpdateColumn("name", "hello") db.Model(&user).UpdateColumn("name", "hello")

View File

@ -11,6 +11,9 @@ func CommitOrRollbackTransaction(scope *Scope) {
} }
func SaveBeforeAssociations(scope *Scope) { func SaveBeforeAssociations(scope *Scope) {
if !scope.shouldSaveAssociations() {
return
}
for _, field := range scope.Fields() { for _, field := range scope.Fields() {
if scope.changeableField(field) && !field.IsBlank && !field.IsIgnored { if scope.changeableField(field) && !field.IsBlank && !field.IsIgnored {
if relationship := field.Relationship; relationship != nil && relationship.Kind == "belongs_to" { if relationship := field.Relationship; relationship != nil && relationship.Kind == "belongs_to" {
@ -25,6 +28,9 @@ func SaveBeforeAssociations(scope *Scope) {
} }
func SaveAfterAssociations(scope *Scope) { func SaveAfterAssociations(scope *Scope) {
if !scope.shouldSaveAssociations() {
return
}
for _, field := range scope.Fields() { for _, field := range scope.Fields() {
if scope.changeableField(field) && !field.IsBlank && !field.IsIgnored { if scope.changeableField(field) && !field.IsBlank && !field.IsIgnored {
if relationship := field.Relationship; relationship != nil && if relationship := field.Relationship; relationship != nil &&

View File

@ -266,6 +266,7 @@ func (s *DB) UpdateColumn(attrs ...interface{}) *DB {
func (s *DB) UpdateColumns(values interface{}) *DB { func (s *DB) UpdateColumns(values interface{}) *DB {
return s.clone().NewScope(s.Value). return s.clone().NewScope(s.Value).
Set("gorm:update_column", true). Set("gorm:update_column", true).
Set("gorm:save_associations", false).
InstanceSet("gorm:update_interface", values). InstanceSet("gorm:update_interface", values).
callCallbacks(s.parent.callback.updates).db callCallbacks(s.parent.callback.updates).db
} }

View File

@ -398,3 +398,11 @@ func (scope *Scope) changeableField(field *Field) bool {
return !field.IsIgnored return !field.IsIgnored
} }
func (scope *Scope) shouldSaveAssociations() bool {
saveAssociations, ok := scope.Get("gorm:save_associations")
if ok && !saveAssociations.(bool) {
return false
}
return true
}

View File

@ -382,3 +382,32 @@ func TestOmitWithUpdateColumn(t *testing.T) {
t.Errorf("Should omit name column when update user") t.Errorf("Should omit name column when update user")
} }
} }
func TestUpdateColumnsSkipsAssociations(t *testing.T) {
user := getPreparedUser("update_columns_user", "special_role")
user.Age = 99
address1 := "first street"
user.BillingAddress = Address{Address1: address1}
DB.Save(user)
// Update a single field of the user and verify that the changed address is not stored.
newAge := int64(100)
user.BillingAddress.Address1 = "second street"
db := DB.Model(user).UpdateColumns(User{Age: newAge})
if db.RowsAffected != 1 {
t.Errorf("Expected RowsAffected=1 but instead RowsAffected=%v", DB.RowsAffected)
}
// Verify that Age now=`newAge`.
freshUser := &User{Id: user.Id}
DB.First(freshUser)
if freshUser.Age != newAge {
t.Errorf("Expected freshly queried user to have Age=%v but instead found Age=%v", newAge, freshUser.Age)
}
// Verify that user's BillingAddress.Address1 is not changed and is still "first street".
DB.First(&freshUser.BillingAddress, freshUser.BillingAddressID)
if freshUser.BillingAddress.Address1 != address1 {
t.Errorf("Expected user's BillingAddress.Address1=%s to remain unchanged after UpdateColumns invocation, but BillingAddress.Address1=%s", address1, freshUser.BillingAddress.Address1)
}
}