gorm默认值不更新问题

问题描述

原有数据结构,如下:

type AdvConfirm struct {
	ID               int       `gorm:"column:id;primary_key" json:"id"`
	StaffID          int       `gorm:"column:staff_id" json:"staff_id"`
	AdvertiserID     int       `gorm:"column:advertiser_id" json:"advertiser_id"`
	ProductID        int       `gorm:"column:product_id" json:"product_id"`
	IsConfirmed      int       `gorm:"column:is_confirmed" json:"is_confirmed"`
	Charge           float64   `gorm:"column:charge" json:"charge"`
	DiscountCharge   float64   `gorm:"column:discount_charge" json:"discount_charge"`
	ActivationCharge float64   `gorm:"column:activation_charge" json:"activation_charge"`
	RebateCharge     float64   `gorm:"column:rebate_charge" json:"rebate_charge"`
	CleaningCharge   float64   `gorm:"column:cleaning_charge" json:"cleaning_charge"`
	ChargeMonth      string    `gorm:"column:charge_month" json:"charge_month"`
	CreatedAt        time.Time `gorm:"column:created_at" json:"created_at"`
	UpdatedAt        time.Time `gorm:"column:updated_at" json:"updated_at"`
}

现在,通过如下方式更新数据库:

func (ac *AdvConfirm) TableName() string {
	return "adv_confirm"
}

func (ac *AdvConfirm) UpdateOperatorStatus() error {
	db, err := GetGormDB()
	if err != nil {
		return err
	}
	
	var m AdvConfirm
	if acc.ID == 0 { // 插入
		err = db.Create(ac).Error
	} else {
		err = db.Debug().Model(&m).Updates(ac).Error
	}
	if err != nil {
		return err
	}

	return nil
}

发现,当更改IsConfirmed字段的值从0改为1时,正常更新;当更新IsConfirmed字段的值从1改到0时,数据库中该字段的值还是1,该字段没有正常更新,但是其他非零值字段都更新为想要的值了。
这就有点纳闷了,通过查阅gorm官方文档,发现通过Struct的方式更新字段时,对于零值不会被更新。如果想正常更新零值,应该使用map的方式进行更新操作。

提示: 通过结构体变量更新字段值, gorm库会忽略零值字段。就是字段值等于0, nil, “”, false这些值会被忽略掉,不会更新。如果想更新零值,可以使用map类型替代结构体。

通过如下map的形式更新,即可正常更新零值的情况:

func (ac *AdvConfirm) UpdateOperatorStatus() error {
	db, err := GetGormDB()
	if err != nil {
		return err
	}

	if ac.ID == 0 { // 插入
		err = db.Create(ac).Error
	} else {
		err = db.Debug().Model(acc).Updates(map[string]interface{}{"id": ac.ID, "staff_id": ac.StaffID, "advertiser_id": ac.AdvertiserID, "product_id": ac.ProductID, "is_confirmed": ac.IsConfirmed, "charge": ac.Charge, "discount_charge": ac.DiscountCharge, "activation_charge": ac.ActivationCharge, "rebate_charge": ac.RebateCharge, "cleaning_charge": ac.CleaningCharge, "charge_month": ac.ChargeMonth}).Error
	}
	if err != nil {
		return err
	}

	return nil
}

gorm更新方式

保存所有字段

Save 会保存所有的字段,即使字段是零值

db.First(&user)

user.Name = "jinzhu 2"
user.Age = 100
db.Save(&user)
// UPDATE users SET name='jinzhu 2', age=100, birthday='2016-01-01', updated_at = '2013-11-17 21:34:10' WHERE id=111;

更新单个列

当使用 Update 更新单个列时,你需要指定条件,否则会返回 ErrMissingWhereClause 错误,查看 Block Global Updates 获取详情。当使用了 Model 方法,且该对象主键有值,该值会被用于构建条件,例如:

// 条件更新
db.Model(&User{}).Where("active = ?", true).Update("name", "hello")
// 等价于更新SQL语句:UPDATE users SET name='hello', updated_at='2013-11-17 21:34:10' WHERE active=true;

// User 的 ID 是 `111`
db.Model(&user).Update("name", "hello")
// UPDATE users SET name='hello', updated_at='2013-11-17 21:34:10' WHERE id=111;

// 根据条件和 model 的值进行更新
db.Model(&user).Where("active = ?", true).Update("name", "hello")
// UPDATE users SET name='hello', updated_at='2013-11-17 21:34:10' WHERE id=111 AND active=true;

更新多列

Updates 方法支持 struct 和 map[string]interface{} 参数。当使用 struct 更新时,默认情况下,GORM 只会更新非零值的字段

根据 struct 更新属性,只会更新非零值的字段

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;由于Active字段是bool类型的零值false,这里使用结构体更新,不会更新该字段的零值

根据 map 更新所有属性,包括零值字段

db.Model(&user).Updates(map[string]interface{}{"name": "hello", "age": 18, "active": false})
// UPDATE users SET name='hello', age=18, active=false, updated_at='2013-11-17 21:34:10' WHERE id=111;

注意 当通过 struct 更新时,GORM 只会更新非零字段。 如果想确保指定字段被更新,应该使用 Select 更新选定字段,或使用 map 来完成所有属性(包括零值字段)更新操作。

更新选定字段

如果想要在更新时,只指定或忽略某些字段进行更新,可以使用 Select、Omit方法。

// 使用 Map 进行 Select
// User's ID is `111`:
db.Model(&user).Select("name").Updates(map[string]interface{}{"name": "hello", "age": 18, "active": false})
// UPDATE users SET name='hello' WHERE id=111;虽然map中包括多个字段,但是更新时调用Select方法只指定name字段更新

db.Model(&user).Omit("name").Updates(map[string]interface{}{"name": "hello", "age": 18, "active": false})
// UPDATE users SET age=18, active=false, updated_at='2013-11-17 21:34:10' WHERE id=111;这里使用Omit指定更新时要忽略的字段,即对该字段不更新

// 使用 Struct 进行 Select(会 select 零值的字段)
db.Model(&user).Select("Name", "Age").Updates(User{Name: "new_name", Age: 0})
// UPDATE users SET name='new_name', age=0 WHERE id=111;

// Select 所有字段(查询包括零值字段的所有字段)
db.Model(&user).Select("*").Update(User{Name: "jinzhu", Role: "admin", Age: 0})

// Select 除 Role 外的所有字段(包括零值字段的所有字段)
db.Model(&user).Select("*").Omit("Role").Update(User{Name: "jinzhu", Role: "admin", Age: 0})

更新 Hook

对于更新操作,GORM 支持 BeforeSave、BeforeUpdate、AfterSave、AfterUpdate 钩子,这些方法将在更新记录时被调用。

func (u *User) BeforeUpdate(tx *gorm.DB) (err error) {
    if u.Role == "admin" {
        return errors.New("admin user not allowed to update")
    }
    return
}

批量更新

如果没有通过 Model 指定记录的主键,则 GORM 会执行批量更新

// 根据 struct 更新
db.Model(User{}).Where("role = ?", "admin").Updates(User{Name: "hello", Age: 18})
// UPDATE users SET name='hello', age=18 WHERE role = 'admin; 更新所有role为admin的记录

// 根据 map 更新
db.Table("users").Where("id IN ?", []int{10, 11}).Updates(map[string]interface{}{"name": "hello", "age": 18})
// UPDATE users SET name='hello', age=18 WHERE id IN (10, 11);

阻止全局更新
如果在没有任何条件的情况下执行批量更新,默认情况下,GORM 不会执行该操作,并返回 ErrMissingWhereClause 错误

对此,你必须加一些条件,或者使用原生 SQL,或者启用 AllowGlobalUpdate 模式,例如:

db.Model(&User{}).Update("name", "jinzhu").Error // gorm.ErrMissingWhereClause

db.Model(&User{}).Where("1 = 1").Update("name", "jinzhu")
// UPDATE users SET `name` = "jinzhu" WHERE 1=1

db.Exec("UPDATE users SET name = ?", "jinzhu")
// UPDATE users SET name = "jinzhu"

db.Session(&gorm.Session{AllowGlobalUpdate: true}).Model(&User{}).Update("name", "jinzhu")
// UPDATE users SET `name` = "jinzhu"

更新的记录数

可以通过 RowsAffected 获取受更新影响的行数。

result := db.Model(User{}).Where("role = ?", "admin").Updates(User{Name: "hello", Age: 18})
// UPDATE users SET name='hello', age=18 WHERE role = 'admin;

result.RowsAffected // 更新的记录数
result.Error        // 更新的错误

总结

通过结构体变量更新字段值, gorm库会忽略零值字段。即:通过update struct的方式更新值时,当字段值等于0, nil, “”, false这些值会被忽略掉,这些值不会更新。如果想更新零值,可以使用updates map类型替代结构体。

参考

GORM更新操作

  • 6
    点赞
  • 11
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

love666666shen

谢谢您的鼓励!

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值