# 鉤子
## 對象生命周期
鉤子是在創建、查詢、更新、刪除等操作之前、之后調用的函數。
如果您已經為模型定義了指定的方法,它會在創建、更新、查詢、刪除時自動被調用。如果任何回調返回錯誤,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
}
```