golang gorm 使用泛型实现公共方法

发布时间: 更新时间: 总字数:678 阅读时间:2m 作者: IP上海 分享 网址

Go 1.18+ 中,可以通过泛型结合 GORM 实现通用数据库操作。以下是一个实现通用 CRUD 方法的示例:

package repository

import (
    "gorm.io/gorm"
)

// 定义模型必须实现的接口(例如包含ID字段)
type Model interface {
    TableName() string
    // 可以添加其他需要实现的约束方法,例如:
    // GetID() uint
}

// 通用 Repository 结构体
type GenericRepository[T Model] struct {
    DB *gorm.DB
}

func NewRepository[T Model](db *gorm.DB) *GenericRepository[T] {
    return &GenericRepository[T]{DB: db}
}

// FindByID 根据ID查询记录
func (r *GenericRepository[T]) FindByID(id uint) (*T, error) {
    var entity T
    if err := r.DB.First(&entity, id).Error; err != nil {
        return nil, err
    }
    return &entity, nil
}

// Create 创建新记录
func (r *GenericRepository[T]) Create(entity *T) error {
    return r.DB.Create(entity).Error
}

// Update 更新记录
func (r *GenericRepository[T]) Update(entity *T) error {
    return r.DB.Save(entity).Error
}

// Delete 删除记录
func (r *GenericRepository[T]) Delete(id uint) error {
    var entity T
    return r.DB.Delete(&entity, id).Error
}

// FindAll 查询所有记录(带分页)
func (r *GenericRepository[T]) FindAll(page, pageSize int) ([]T, int64, error) {
    var (
        entities []T
        count    int64
    )

    db := r.DB.Model(&entities)
    db.Count(&count)

    if page > 0 && pageSize > 0 {
        offset := (page - 1) * pageSize
        db = db.Offset(offset).Limit(pageSize)
    }

    if err := db.Find(&entities).Error; err != nil {
        return nil, 0, err
    }

    return entities, count, nil
}

// Where 条件查询
func (r *GenericRepository[T]) Where(query interface{}, args ...interface{}) *GenericRepository[T] {
    r.DB = r.DB.Where(query, args...)
    return r
}

// WithPreloads 预加载关联
func (r *GenericRepository[T]) WithPreloads(preloads ...string) *GenericRepository[T] {
    for _, preload := range preloads {
        r.DB = r.DB.Preload(preload)
    }
    return r
}

使用示例:

// 定义模型
type User struct {
    gorm.Model
    Name  string
    Email string `gorm:"uniqueIndex"`
}

// 实现 Model 接口
func (User) TableName() string {
    return "users"
}

func main() {
    // 初始化数据库连接
    db, _ := gorm.Open(sqlite.Open("test.db"), &gorm.Config{})

    // 自动迁移
    db.AutoMigrate(&User{})

    // 创建 Repository
    userRepo := repository.NewRepository[User](db)

    // 使用示例
    newUser := &User{Name: "John", Email: "[email protected]"}
    userRepo.Create(newUser)

    // 查询用户
    user, _ := userRepo.FindByID(1)
    fmt.Println(user)

    // 条件查询
    users, _, _ := userRepo.Where("name LIKE ?", "%John%").FindAll(1, 10)
}

关键点说明:

  1. 类型约束:通过 Model 接口确保泛型类型符合数据库模型的基本要求
  2. 通用操作:封装了常见的 CRUD 操作,减少重复代码
  3. 链式调用:通过返回 Repository 指针实现链式调用
  4. 扩展性:可以方便地添加事务支持、软删除处理等
  5. 类型安全:泛型保证了返回结果的类型正确性

进阶优化方向:

  1. 添加事务支持
  2. 处理软删除(DeletedAt)
  3. 添加缓存层
  4. 支持更复杂的查询构建
  5. 增加乐观锁机制
  6. 添加钩子函数支持
  7. 支持多数据库方言

注意:使用泛型时要注意 Go 的类型系统的限制,复杂查询可能仍需要特殊处理。对于关联关系的处理,建议结合预加载方法 (Preload) 来实现。

Home Archives Categories Tags Statistics
本文总阅读量 次 本站总访问量 次 本站总访客数