全部学科
NodeJS全栈
nodejs
Python全栈
python
小程序首页
📅 2026-05-21 6 分钟 ✍️ juanwangdev

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 在每次 FindFirstTake 等查询后执行,避免在其中执行耗时操作。

钩子中修改结构体字段会影响返回结果,但不会持久化到数据库。

批量查询时 AfterFind 会对每条记录执行,需注意性能影响。

加载关联数据推荐使用 PreloadJoins,而非在钩子中手动查询。

要点总结

  • AfterFind 钩子在查询完成后对每条记录执行自定义逻辑
  • 适用于字段格式化、脱敏、计算字段生成等场景
  • 可手动加载关联数据,但需注意 N+1 查询性能问题
  • 钩子中修改字段仅影响返回结果,不持久化到数据库
  • 关联加载推荐使用 Preload 替代钩子手动查询

存放路径:D:\git2\jwdev\articles\GORM\进阶\钩子函数与回调机制\查询钩子实现.md

📝 发现内容有误?点击此处直接编辑

← 上一篇 GORM 更新钩子实现
下一篇 → GORM 慢查询监控
想查看更多题目和详细解析?
小程序提供完整的题库、模拟考试和详细解析
马上就来

长按或扫描二维码,立即体验

扫码体验小程序
马上就来
使用微信扫描二维码
立即体验完整题库