GORM 查询钩子实现
GORM 钩子允许在查询完成后执行自定义逻辑,适用于数据格式化与关联数据加载。
AfterFind 钩子
接口定义
Go
type Model interface {
AfterFind(tx *gorm.DB) error
}
基本实现
Go
type User struct {
ID uint
Name string
AvatarURL string
Role string
}
func (u *User) AfterFind(tx *gorm.DB) error {
// 处理头像 URL
if u.AvatarURL != "" && !strings.HasPrefix(u.AvatarURL, "http") {
u.AvatarURL = "https://cdn.example.com" + u.AvatarURL
}
return nil
}
数据格式化
字段脱敏
Go
func (u *User) AfterFind(tx *gorm.DB) error {
// 手机号脱敏
if len(u.Phone) == 11 {
u.Phone = u.Phone[:3] + "****" + u.Phone[7:]
}
return nil
}
时间格式转换
Go
func (o *Order) AfterFind(tx *gorm.DB) error {
// 时间戳转可读格式
o.CreatedAtStr = o.CreatedAt.Format("2006-01-02 15:04:05")
return nil
}
关联加载
手动加载关联
Go
type Post struct {
ID uint
Title string
Author *User
AuthorID uint
Comments []Comment
}
func (p *Post) AfterFind(tx *gorm.DB) error {
// 加载作者
if p.AuthorID > 0 {
tx.First(&p.Author, p.AuthorID)
}
// 加载评论
tx.Where("post_id = ?", p.ID).Find(&p.Comments)
return nil
}
AfterFind 中加载关联需注意 N+1 查询问题,建议使用 Preload 替代。
条件处理
根据状态处理
Go
func (o *Order) AfterFind(tx *gorm.DB) error {
switch o.Status {
case "paid":
o.StatusText = "已支付"
case "shipped":
o.StatusText = "已发货"
default:
o.StatusText = "未知状态"
}
return nil
}
注意事项
AfterFind在每次Find、First、Take等查询后执行,避免在其中执行耗时操作。
钩子中修改结构体字段会影响返回结果,但不会持久化到数据库。
批量查询时
AfterFind会对每条记录执行,需注意性能影响。
加载关联数据推荐使用
Preload或Joins,而非在钩子中手动查询。
要点总结
AfterFind钩子在查询完成后对每条记录执行自定义逻辑- 适用于字段格式化、脱敏、计算字段生成等场景
- 可手动加载关联数据,但需注意 N+1 查询性能问题
- 钩子中修改字段仅影响返回结果,不持久化到数据库
- 关联加载推荐使用
Preload替代钩子手动查询
存放路径:D:\git2\jwdev\articles\GORM\进阶\钩子函数与回调机制\查询钩子实现.md
📝 发现内容有误?点击此处直接编辑