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