Reputation: 6321
On updates
gorm doesnt update boolean type to false
. By default it updates to true
, but when i try to update to false
not changes. I dont see any errors also. What can be the issue ?
type Attendee struct {
ID uint `gorm:"primary_key" gorm:"AUTO_INCREMENT" json:"id,omitempty" mapstructure:"id" csv:"ID"`
Email string `json:"email,omitempty" mapstructure:"email" csv:"Email,required"`
ShowDirectory bool `json:"show_directory,omitempty" gorm:"default:true" mapstructure:"show_directory" csv:"-"`
}
var attendee Attendee
// JSON.unmarshal lines here for the &attendee
if err := service.DB.Model(&attendee).Updates(Attendee{
Email: attendee.Email,
ShowDirectory: false
}).Error; err != nil {
return Attendee{}, err
}
Alternate Solution:
This works, but I am updating multiple attributies. So, I cant use this.
att := Attendee{ID: 1}
service.DB.Model(&att).Update("ShowDirectory", false)
Upvotes: 29
Views: 35120
Reputation: 473
you can use pointer field and mapstructure tag. so when you need a update data, you can implement a function like this:
func (m *Model) ToMap() map[string]interface{} {
var updateData map[string]interface{}
err := mapstructure.Decode(m, &updateData)
if err != nil {
return nil
}
return updateData
}
This implementation also work when you create a Filter struct
query := txn.Model(&Model{}).Clauses(clause.Returning{})
conditions := filter.ToMap()
if len(conditions) > 0 {
query = query.Where(conditions)
}
Upvotes: 0
Reputation: 2928
TL;DR: if you want to update all fields, use the Save()
method instead of Updates()
.
As other answers have pointed out, Updates()
will not update zero field values. That's because GORM can't tell the difference between
Attendee{Email: "...", ShowDirectory: false}
and Attendee{Email: "..."}
.
To update all field values and avoid specifying field names as strings, you can read the record, change field values, and save the record. It's better to do this in a single transaction to avoid race conditions:
err := db.Transaction(func(db *gorm.DB) error {
// read the existing record
var a Attendee
if res := db.Where("id = ?", attendeeId).First(&a); res.Error != nil {
return err
}
// update the fields
a.Email = newEmail
a.ShowDirectory = newShowDirectory
// save the record
if res := db.Save(&a); res.Error != nil {
return err
}
return nil
})
Upvotes: 1
Reputation: 1493
Another convenient way would be making that field as a pointer.
NOTE all fields having a zero value, like 0, '', false or other zero values, won’t be saved into the database but will use its default value. If you want to avoid this, consider using a pointer type or scanner/valuerLink
In your case, the model would look like:
type Attendee struct {
ID uint `gorm:"primary_key" gorm:"AUTO_INCREMENT" json:"id,omitempty" mapstructure:"id" csv:"ID"`
Email string `json:"email,omitempty" mapstructure:"email" csv:"Email,required"`
ShowDirectory *bool `json:"show_directory,omitempty" gorm:"default:true" mapstructure:"show_directory" csv:"-"`
}
Upvotes: 19
Reputation: 475
Simply add `Select(*)
db.Model(&user).Select("*").Update(User{Name: "jinzhu", Role: "admin", Age: 0})
This way is much more simpler than others.
Upvotes: -1
Reputation: 595
As it's mentioned from the document, to set a falsy value you need to use map
or select the columns you need.
When update with struct, GORM will only update non-zero fields, you might want to use map to update attributes or use Select to specify fields to update
// Select with Struct (select zero value fields)
db.Model(&user).Select("Name", "Age").Updates(User{Name: "new_name", Age: 0})
// UPDATE users SET name='new_name', age=0 WHERE id=111;
or you can select all columns:
// Select all fields (select all fields include zero value fields)
db.Model(&user).Select("*").Update(User{Name: "jinzhu", Role: "admin", Age: 0})
Upvotes: 3
Reputation: 6321
As @mkopriva mentioned, by GORM Documentation
// Update attributes with `struct`, will only update non-zero fields db.Model(&user).Updates(User{Name: "hello", Age: 18, Active: false}) // UPDATE users SET name='hello', age=18, updated_at = '2013-11-17 > 21:34:10' WHERE id = 111; // Update attributes with `map` db.Model(&user).Updates(map[string]interface{}{"name": "hello", "age": 18, "actived": false}) // UPDATE users SET name='hello', age=18, actived=false, updated_at='2013-11-17 21:34:10' WHERE id=111;
NOTE When update with struct, GORM will only update non-zero fields, you might want to use
map
to update attributes or useSelect
to specify fields to update
Solved:
if err := service.DB.Model(&attendee).Updates(map[string]interface{}{
"Email": attendee.Email,
"ShowDirectory": false
}).Error; err != nil {
return Attendee{}, err
}
Upvotes: 32
Reputation: 4133
Please do not use go struct for updating the non-zero fields such as boolean:false
The below code will not update Active: false
in your database and gorm simply ignore
db.Model(&user).Updates(User{Name: "hello", Age: 18, Active: false})
// UPDATE users SET name='hello', age=18, updated_at = '2013-11-17 21:34:10' WHERE id = 111;
The below code will update the Active: false
db.Model(&user).Updates(map[string]interface{}{"name": "hello", "age": 18, "actived": false})
// UPDATE users SET name='hello', age=18, actived=false, updated_at='2013-11-17 21:34:10' WHERE id=111;
Use Map instead of go struct
Upvotes: 0
Reputation: 65
You should write gorm type in your struct, something like this:
gorm:"type:boolean; column:column_name"
and for sure it will work!
Upvotes: 0