对象生命周期
Hook 是在创建、查询、更新、删除等操作之前、之后调用的函数。
如果您已经为模型定义了指定的方法,它会在创建、更新、查询、删除时自动被调用。如果任何回调返回错误,GORM 将停止后续的操作并回滚事务。
钩子方法的函数签名应该是 func(*gorm.DB) error
Hook
创建对象
创建时可用的 hook
1. // 开始事务
2. BeforeSave
3. BeforeCreate
4. // 关联前的 save
5. // 插入记录至 db
6. // 关联后的 save
7. AfterCreate
8. AfterSave
9. // 提交或回滚事务
代码示例:
1. func (u *User) BeforeCreate(tx *gorm.DB) (err error) {
2. u.UUID = uuid.New()
4. if !u.IsValid() {
5. err = errors.New("can't save invalid data")
6. }
7. return
8. }
10. func (u *User) AfterCreate(tx *gorm.DB) (err error) {
11. if u.ID == 1 {
12. tx.Model(u).Update("role", "admin")
13. }
14. return
15. }
注意 在 GORM 中保存、删除操作会默认运行在事务上, 因此在事务完成之前该事务中所作的更改是不可见的,如果您的钩子返回了任何错误,则修改将被回滚。
1. func (u *User) AfterCreate(tx *gorm.DB) (err error) {
2. if !u.IsValid() {
3. return errors.New("rollback invalid user")
4. }
5. return nil
6. }
更新对象
更新时可用的 hook
1. // 开始事务
2. BeforeSave
3. BeforeUpdate
4. // 关联前的 save
5. // 更新 db
6. // 关联后的 save
7. AfterUpdate
8. AfterSave
9. // 提交或回滚事务
代码示例:
1. func (u *User) BeforeUpdate(tx *gorm.DB) (err error) {
2. if u.readonly() {
3. err = errors.New("read only user")
4. }
5. return
6. }
8. // 在同一个事务中更新数据
9. func (u *User) AfterUpdate(tx *gorm.DB) (err error) {
10. if u.Confirmed {
11. tx.Model(&Address{}).Where("user_id = ?", u.ID).Update("verfied", true)
12. }
13. return
14. }
删除对象
删除时可用的 hook
1. // 开始事务
2. BeforeDelete
3. // 删除 db 中的数据
4. AfterDelete
5. // 提交或回滚事务
代码示例:
1. // 在同一个事务中更新数据
2. func (u *User) AfterDelete(tx *gorm.DB) (err error) {
3. if u.Confirmed {
4. tx.Model(&Address{}).Where("user_id = ?", u.ID).Update("invalid", false)
5. }
6. return
7. }
查询对象
查询时可用的 hook
1. // 从 db 中加载数据
2. // Preloading (eager loading)
3. AfterFind
代码示例:
1. func (u *User) AfterFind(tx *gorm.DB) (err error) {
2. if u.MemberShip == "" {
3. u.MemberShip = "user"
4. }
5. return
6. }
修改当前操作
1. func (u *User) BeforeCreate(tx *gorm.DB) error {
2. // 通过 tx.Statement 修改当前操作,例如:
3. tx.Statement.Select("Name", "Age")
4. tx.Statement.AddClause(clause.OnConflict{DoNothing: true})
6. // tx 是带有 `NewDB` 选项的新会话模式
7. // 基于 tx 的操作会在同一个事务中,但不会带上任何当前的条件
8. err := tx.First(&role, "name = ?", user.Role).Error
9. // SELECT * FROM roles WHERE name = "admin"
10. // ...
11. return err
12. }
