删除记录时,GORM 会依次触发 BeforeDelete、AfterDelete 钩子。
删除记录前执行:
func (u *User) BeforeDelete(tx *gorm.DB) error {
if u.Role == "admin" {
return errors.New("不能删除管理员")
}
return nil
}
删除记录后执行:
func (u *User) AfterDelete(tx *gorm.DB) error {
return tx.Delete(&UserProfile{}, "user_id = ?", u.ID).Error
}
删除记录时的完整顺序:
BeforeDelete
↓
执行 DELETE
↓
AfterDelete
软删除也会触发钩子:
type User struct {
gorm.Model
Name string
}
func (u *User) BeforeDelete(tx *gorm.DB) error {
fmt.Println("BeforeDelete 触发")
return nil
}
db.Delete(&user)
软删除执行的是 UPDATE,但仍然触发删除钩子。
Unscoped().Delete() 触发同样的钩子:
func (u *User) BeforeDelete(tx *gorm.DB) error {
if tx.Statement.Unscoped {
fmt.Println("真正删除")
} else {
fmt.Println("软删除")
}
return nil
}
db.Unscoped().Delete(&user)
判断是软删除还是真正删除:
func (u *User) BeforeDelete(tx *gorm.DB) error {
if tx.Statement.Unscoped {
var orders []Order
if err := tx.Where("user_id = ?", u.ID).Find(&orders).Error; err != nil {
return err
}
if len(orders) > 0 {
return errors.New("用户有订单记录,不能删除")
}
}
return nil
}
在钩子中删除关联数据:
func (u *User) BeforeDelete(tx *gorm.DB) error {
if err := tx.Where("user_id = ?", u.ID).Delete(&Order{}).Error; err != nil {
return err
}
if err := tx.Where("user_id = ?", u.ID).Delete(&UserProfile{}).Error; err != nil {
return err
}
return nil
}
删除前备份到历史表:
func (u *User) BeforeDelete(tx *gorm.DB) error {
history := UserHistory{
UserID: u.ID,
Name: u.Name,
Email: u.Email,
DeletedAt: time.Now(),
}
return tx.Create(&history).Error
}
根据条件决定是否允许删除:
func (o *Order) BeforeDelete(tx *gorm.DB) error {
if o.Status == "paid" || o.Status == "shipped" {
return errors.New("已支付或已发货的订单不能删除")
}
return nil
}
记录删除操作:
func (u *User) AfterDelete(tx *gorm.DB) error {
log := AuditLog{
Table: "users",
Action: "delete",
RecordID: u.ID,
UserID: getCurrentUserID(tx),
CreatedAt: time.Now(),
}
return tx.Create(&log).Error
}
批量删除不触发钩子:
db.Where("status = ?", "inactive").Delete(&User{})
如果需要触发钩子,逐条删除:
var users []User
db.Where("status = ?", "inactive").Find(&users)
for _, user := range users {
db.Delete(&user)
}
db.Session(&gorm.Session{SkipHooks: true}).Delete(&user)
用户删除
func (u *User) BeforeDelete(tx *gorm.DB) error {
if u.Role == "admin" {
return errors.New("管理员不能删除")
}
var orders int64
tx.Model(&Order{}).Where("user_id = ? AND status IN ?", u.ID, []string{"paid", "shipped"}).Count(&orders)
if orders > 0 {
return errors.New("用户有进行中的订单,不能删除")
}
return nil
}
func (u *User) AfterDelete(tx *gorm.DB) error {
tx.Where("user_id = ?", u.ID).Delete(&UserProfile{})
tx.Where("user_id = ?", u.ID).Delete(&UserSetting{})
return nil
}
订单删除
func (o *Order) BeforeDelete(tx *gorm.DB) error {
if o.Status == "paid" {
return errors.New("已支付订单不能删除,请申请退款")
}
if o.Status == "shipped" {
return errors.New("已发货订单不能删除")
}
return nil
}
func (o *Order) AfterDelete(tx *gorm.DB) error {
return tx.Where("order_id = ?", o.ID).Delete(&OrderItem{}).Error
}
文件删除
type File struct {
ID uint
Path string
Size int64
}
func (f *File) AfterDelete(tx *gorm.DB) error {
if f.Path != "" {
os.Remove(f.Path)
}
return nil
}
删除钩子适合处理删除前验证、级联删除、审计日志等逻辑。注意软删除也会触发钩子,批量删除不会触发钩子。