关于 golang 的 Gorm 中钩子函数的示例
// 若想在更新时跳过钩子方法且不追踪更新时间,可使用 UpdateColumn、UpdateColumns 方法
// 更新单个列
db.Model(&user).UpdateColumn("name", "hello")
// UPDATE users SET name='hello' WHERE id = 111;
// 更新多个列
db.Model(&user).UpdateColumns(User{Name: "hello", Age: 18})
// UPDATE users SET name='hello', age=18 WHERE id = 111;
// 更新特定列
db.Model(&user).Select("name", "age").UpdateColumns(User{Name: "hello", Age: 0})
// UPDATE users SET name='hello', age=0 WHERE id = 111;
// -------------------------------------------------------------------------- 检查字段是否被改变
// Changed 方法可以被用在 BeforeUpdate 钩子中,它返回字段是否有变更的布尔值
// Changed 方法只能与 Update、Updates 方法一起使用
// 并且它只检查 Model 对象字段的值与 Update、Updates 的值是否相等,若值有变更且字段没有被忽略,则返回 true
func (u *User) BeforeUpdate(tx *gorm.DB) (err error) {
// 若 Role 字段有变更
if tx.Statement.Changed("Role") {
return errors.New("role not allowed to change")
}
// 若 Name 或 Role 字段有变更
if tx.Statement.Changed("Name", "Admin") {
tx.Statement.SetColumn("Age", 18)
}
// 若任意字段有变更
if tx.Statement.Changed() {
tx.Statement.SetColumn("RefreshedAt", time.Now())
}
return nil
}
db.Model(&User{ID: 1, Name: "jinzhu"}).Updates(map[string]interface{"name": "jinzhu2"})
// Changed("Name") => true
db.Model(&User{ID: 1, Name: "jinzhu"}).Updates(map[string]interface{"name": "jinzhu"})
// Changed("Name") => false, 因为 `Name` 没有变更
db.Model(&User{ID: 1, Name: "jinzhu"}).Select("Admin").Updates(map[string]interface{
"name": "jinzhu2", "admin": false,
})
// Changed("Name") => false, 因为 `Name` 没有被 Select 选中并更新
db.Model(&User{ID: 1, Name: "jinzhu"}).Updates(User{Name: "jinzhu2"})
// Changed("Name") => true
db.Model(&User{ID: 1, Name: "jinzhu"}).Updates(User{Name: "jinzhu"})
// Changed("Name") => false, 因为 `Name` 未变更
db.Model(&User{ID: 1, Name: "jinzhu"}).Select("Admin").Updates(User{Name: "jinzhu2"})
// Changed("Name") => false, 因为 `Name` 没有被 Select 选中并更新
// -------------------------------------------------------------------------- 在 Update 时修改值
// 若要在 Before 钩子中改变要更新的值
// 如果它是一个完整的更新,可以使用 Save,否则,应使用 SetColumn,例如:
func (user *User) BeforeSave(tx *gorm.DB) (err error) {
if pw, err := bcrypt.GenerateFromPassword(user.Password, 0); err == nil {
tx.Statement.SetColumn("EncryptedPassword", pw)
}
if tx.Statement.Changed("Code") {
user.Age += 20
tx.Statement.SetColumn("Age", user.Age)
}
}
db.Model(&user).Update("Name", "jinzhu")
// -------------------------------------------------------------------------- 在 Update 时修改值
// 可以在 BeforeSave 钩子中改变要更新的值
// 如果它是一个完整的更新,则可以使用 Save 方法,否则应使用 SetColumn 方法,例如:
func (user *User) BeforeSave(tx *gorm.DB) (err error) {
if pw, err := bcrypt.GenerateFromPassword(user.Password, 0); err == nil {
tx.Statement.SetColumn("EncryptedPassword", pw)
}
if tx.Statement.Changed("Code") {
user.Age += 20
tx.Statement.SetColumn("Age", user.Age)
}
}
db.Model(&user).Update("Name", "jinzhu")