GORM模型更新
一、更新所有字段
Save()
默认会更新该对象的所有字段,即使你没有赋值。
package main
import (
"fmt"
"gorm.io/driver/mysql"
"gorm.io/gorm"
)
type UsersUpdate struct {
gorm.Model
//Name *string `gorm:"type:varchar(100);default:RandySun;comment:姓名"`
Name string `gorm:"type:varchar(100);default:RandySun;comment:姓名"`
Age int64
// 设置默认值
Active bool
}
func main() {
dsn := "root:@tcp(127.0.0.1:3306)/gorm?charset=utf8mb4&parseTime=True&loc=Local"
db, err := gorm.Open(mysql.Open(dsn), &gorm.Config{})
if err != nil {
panic(err)
}
// 迁移表创建对应关系
db.AutoMigrate(&UsersUpdate{})
// 添加数据
db.Debug().Create(&UsersUpdate{Name: "bary", Age: 18})
db.Debug().Create(&UsersUpdate{Name: "RandySun", Age: 18})
db.Debug().Create(&UsersUpdate{Name: "Jack", Age: 18})
db.Debug().Create(&UsersUpdate{Name: "", Age: 19}) // 添加记录name默认为Null
// 查询
var user UsersSelect
db.Debug().First(&user)
fmt.Printf("%#v", user)
// 更新
user.Name = "xiaoSun"
user.Age = 18
// 保存 save默认更新所有字段
// UPDATE `users_updates` SET `created_at`='2021-11-23 22:24:20.984',`updated_at`='2021-11-23 22:27:27.243',`deleted_at`=NULL,`name`='xiaoSun',`age`=18,`active`=false WHERE `id` = 1
db.Debug().Save(&user)
}
UPDATE
users_updatesSET
created_at='2021-11-23 22:24:20.984',
updated_at='2021-11-23 22:27:27.243',
deleted_at=NULL,
name='xiaoSun',
age=18,
active=false WHERE
id = 1
二、更新修改字段
如果你只希望更新指定字段,可以使用Update
或者Updates
2.1更新指定字段
// 根据给定的条件更新单个属性
UPDATE `users_updates` SET `name`='Randy',`updated_at`='2021-11-23 22:52:04.414' WHERE `id` = 1
db.Debug().Model(&user).Update("name","Randy")
2.2 条件更新字段
// 根据给定的条件更新单个属性
// UPDATE `users_updates` SET `name`='bak',`updated_at`='2021-11-23 22:56:37.193' WHERE active = false AND `users_updates`.`deleted_at` IS NULL AND `id` = 1
db.Debug().Model(&user).Where("active = ?", true).Update("name", "hello")
2.3 map 更新多个属性字段
// 使用 map 更新多个属性,只会更新其中有变化的属性
//UPDATE `users_updates` SET `active`=true,`age`=119,`name`='',`updated_at`='2021-11-24 08:24:03.114' WHERE `id` = 1
m1 := map[string]interface{}{
"name":"",
"age": 119,
"active": true,
}
db.Debug().Model(&user).Updates(map[string]interface{}{"name": "hello", "age": 18, "active": false})
2.4 struct 更新多个属性
// 使用 struct 更新多个属性,只会更新其中有变化且为非零值的字段
// UPDATE `users_updates` SET `updated_at`='2021-11-24 08:28:40.079',`name`='hello' WHERE `id` = 1
var user UsersUpdate
db.Debug().First(&user)
db.Debug().Model(&user).Updates(UsersUpdate{Name: "hello", Age: 0, Active: false})
// 警告:当使用 struct 更新时,GORM只会更新那些非零值的字段
// 对于下面的操作,不会发生任何更新,"", 0, false 都是其类型的零值
db.Debug().Model(&user).Updates(User{Name: "", Age: 0, Active: false})
2.5 更新选定字段
如果你想更新或忽略某些字段,你可以使用 Select
,Omit
m1 := map[string]interface{}{
"name":"",
"age": 18,
"active": true,
}
// UPDATE `users_updates` SET `age`=18,`updated_at`='2021-11-24 08:31:31.716' WHERE `id` = 1
// 只更新age字段
db.Debug().Model(&user).Select("age").Updates(m1)
2.6 更新排除字段
m1 := map[string]interface{}{
"name":"Randy",
"age": 188,
"active": false,
}
// 排除m1中active更新其他的字段
// UPDATE `users_updates` SET `age`=188,`name`='Randy',`updated_at`='2021-11-24 08:33:48.312' WHERE `id` = 1
db.Debug().Model(&user).Omit("active").Updates(m1)
2.7 无Hooks更新
上面的更新操作会自动运行 model 的 BeforeUpdate
, AfterUpdate
方法,更新 UpdatedAt
时间戳, 在更新时保存其 Associations
, 如果你不想调用这些方法,你可以使用 UpdateColumn
, UpdateColumns
// 更新单个属性,类似于 `Update`
db.Debug().Model(&user).UpdateColumn("name", "hello")
//// UPDATE users SET name='hello' WHERE id = 111;
// 更新多个属性,类似于 `Updates`
db.Debug().Model(&user).UpdateColumns(User{Name: "hello", Age: 18})
//// UPDATE users SET name='hello', age=18 WHERE id = 111;
三、 批量更新
批量更新时Hooks(钩子函数)
不会运行。
// 批量更新
// UPDATE `users` SET `age`=18,`name`='xiao_zhi' WHERE id IN (3,4)
update_res := db.Debug().Table("users_updates").Where("id IN (?)", []int{3, 4}).Updates(map[string]interface{}{"name": "xiao_zhi", "age": 18})
fmt.Printf("%#v", update_res)
// 使用 `RowsAffected` 获取更新记录总数
rows := update_res.RowsAffected
fmt.Printf("%#v", rows)
// 使用 struct 更新时,只会更新非零值字段,若想更新所有字段,请使用map[string]interface{}
db.Debug().Model(User{}).Updates(User{Name: "hello", Age: 18})
//// UPDATE users SET name='hello', age=18;
// 使用 `RowsAffected` 获取更新记录总数
db.Debug().Model(User{}).Updates(User{Name: "hello", Age: 18}).RowsAffected
四、 使用SQL表达式更新
先查询表中的第一条数据保存至user变量。
4.1 查询更新
var user UsersUpdate
db.Debug().First(&user)
fmt.Printf("%#v", user)
// UPDATE `users_updates` SET `age`=age * 2 + 100,`updated_at`='2021-11-24 08:47:38.193' WHERE `id` = 1
db.Debug().Model(&user).Update("age", gorm.Expr("age * ? + ?", 2, 100))
4.2 map更新
var user UsersUpdate
db.Debug().First(&user)
fmt.Printf("%#v", user)
// UPDATE `users_updates` SET `age`=age * 2 + 100,`updated_at`='2021-11-24 08:54:32.295' WHERE `id` = 1
db.Debug().Model(&user).Updates(map[string]interface{}{"age": gorm.Expr("age * ? + ?", 2, 100)})
4.3 UpdateColumn更新
var user UsersUpdate
db.Debug().First(&user)
fmt.Printf("%#v", user)
// UPDATE `users_updates` SET `age`=age - 1 WHERE `id` = 1
db.Debug().Model(&user).UpdateColumn("age", gorm.Expr("age - ?", 1))
4.3 条件更新
var user UsersUpdate
db.Debug().First(&user)
fmt.Printf("%#v", user)
// UPDATE `users_updates` SET `age`=age - 1 WHERE age > 10 AND `users_updates`.`deleted_at` IS NULL AND `id` = 1
db.Debug().Model(&user).Where("age > 10").UpdateColumn("age", gorm.Expr("age - ?", 1))
4.4 修改Hooks中的值
如果你想修改 BeforeUpdate
, BeforeSave
等 Hooks 中更新的值,你可以使用 scope.SetColumn
, 例如:
func (user *User) BeforeSave(scope *gorm.Scope) (err error) {
if pw, err := bcrypt.GenerateFromPassword(user.Password, 0); err == nil {
scope.SetColumn("EncryptedPassword", pw)
}
}
五、 其它更新选项
var user UsersUpdate
db.Debug().First(&user)
fmt.Printf("%#v", user)
// 为 update SQL 添加其它的 SQL
// UPDATE `users_updates` SET `name`='hello',`updated_at`='2021-11-24 09:01:16.859' WHERE `id` = 1
db.Debug().Model(&user).Set("gorm:update_option", "OPTION (OPTIMIZE FOR UNKNOWN)").Update("name", "hello")