11 KiB
11 KiB
Repository 迁移指南
从传统模式迁移到 BaseRepositoryImpl 模式
步骤 1:修改结构体定义
之前:
type GormExampleRepository struct {
db *gorm.DB
logger *zap.Logger
}
之后:
type GormExampleRepository struct {
*database.BaseRepositoryImpl // 嵌入基础Repository实现
}
步骤 2:修改构造函数
之前:
func NewGormExampleRepository(db *gorm.DB, logger *zap.Logger) ExampleRepository {
return &GormExampleRepository{
db: db,
logger: logger,
}
}
之后:
func NewGormExampleRepository(db *gorm.DB, logger *zap.Logger) ExampleRepository {
return &GormExampleRepository{
BaseRepositoryImpl: database.NewBaseRepositoryImpl(db, logger),
}
}
步骤 3:删除 getDB 方法
删除这样的代码:
func (r *GormExampleRepository) getDB(ctx context.Context) *gorm.DB {
if tx, ok := database.GetTx(ctx); ok {
return tx
}
return r.db
}
步骤 4:实现 Repository[T] 接口方法
基础 CRUD 操作
Create - 之前:
func (r *GormExampleRepository) Create(ctx context.Context, entity Entity) (Entity, error) {
r.logger.Info("创建实体", zap.String("id", entity.ID))
err := r.getDB(ctx).WithContext(ctx).Create(&entity).Error
return entity, err
}
Create - 之后:
func (r *GormExampleRepository) Create(ctx context.Context, entity Entity) (Entity, error) {
r.GetLogger().Info("创建实体", zap.String("id", entity.ID))
err := r.BaseRepositoryImpl.Create(ctx, &entity)
return entity, err
}
GetByID - 之前:
func (r *GormExampleRepository) GetByID(ctx context.Context, id string) (Entity, error) {
var entity Entity
err := r.getDB(ctx).WithContext(ctx).Where("id = ?", id).First(&entity).Error
return entity, err
}
GetByID - 之后:
func (r *GormExampleRepository) GetByID(ctx context.Context, id string) (Entity, error) {
var entity Entity
err := r.BaseRepositoryImpl.GetByID(ctx, id, &entity)
return entity, err
}
Update - 之前:
func (r *GormExampleRepository) Update(ctx context.Context, entity Entity) error {
r.logger.Info("更新实体", zap.String("id", entity.ID))
return r.getDB(ctx).WithContext(ctx).Save(&entity).Error
}
Update - 之后:
func (r *GormExampleRepository) Update(ctx context.Context, entity Entity) error {
r.GetLogger().Info("更新实体", zap.String("id", entity.ID))
return r.BaseRepositoryImpl.Update(ctx, &entity)
}
批量操作
CreateBatch:
func (r *GormExampleRepository) CreateBatch(ctx context.Context, entities []Entity) error {
r.GetLogger().Info("批量创建实体", zap.Int("count", len(entities)))
return r.BaseRepositoryImpl.CreateBatch(ctx, &entities)
}
GetByIDs:
func (r *GormExampleRepository) GetByIDs(ctx context.Context, ids []string) ([]Entity, error) {
var entities []Entity
err := r.BaseRepositoryImpl.GetByIDs(ctx, ids, &entities)
return entities, err
}
UpdateBatch:
func (r *GormExampleRepository) UpdateBatch(ctx context.Context, entities []Entity) error {
r.GetLogger().Info("批量更新实体", zap.Int("count", len(entities)))
return r.BaseRepositoryImpl.UpdateBatch(ctx, &entities)
}
DeleteBatch:
func (r *GormExampleRepository) DeleteBatch(ctx context.Context, ids []string) error {
r.GetLogger().Info("批量删除实体", zap.Strings("ids", ids))
return r.BaseRepositoryImpl.DeleteBatch(ctx, ids, &Entity{})
}
步骤 5:实现 BaseRepository 接口方法
基础操作
Delete:
func (r *GormExampleRepository) Delete(ctx context.Context, id string) error {
r.GetLogger().Info("删除实体", zap.String("id", id))
return r.BaseRepositoryImpl.Delete(ctx, id, &Entity{})
}
Exists:
func (r *GormExampleRepository) Exists(ctx context.Context, id string) (bool, error) {
return r.BaseRepositoryImpl.Exists(ctx, id, &Entity{})
}
Count:
func (r *GormExampleRepository) Count(ctx context.Context, options interfaces.CountOptions) (int64, error) {
// 如果需要自定义搜索逻辑
if options.Search != "" {
return r.CountWhere(ctx, &Entity{}, "name LIKE ? OR description LIKE ?",
"%"+options.Search+"%", "%"+options.Search+"%")
}
return r.BaseRepositoryImpl.Count(ctx, &Entity{}, options)
}
SoftDelete:
func (r *GormExampleRepository) SoftDelete(ctx context.Context, id string) error {
r.GetLogger().Info("软删除实体", zap.String("id", id))
return r.BaseRepositoryImpl.SoftDelete(ctx, id, &Entity{})
}
Restore:
func (r *GormExampleRepository) Restore(ctx context.Context, id string) error {
r.GetLogger().Info("恢复实体", zap.String("id", id))
return r.BaseRepositoryImpl.Restore(ctx, id, &Entity{})
}
列表查询
List:
func (r *GormExampleRepository) List(ctx context.Context, options interfaces.ListOptions) ([]Entity, error) {
var entities []Entity
// 如果需要自定义搜索逻辑
if options.Search != "" {
query := r.GetDB(ctx).Model(&Entity{})
// 应用筛选条件
if options.Filters != nil {
for key, value := range options.Filters {
query = query.Where(key+" = ?", value)
}
}
// 自定义搜索逻辑
query = query.Where("name LIKE ? OR description LIKE ?",
"%"+options.Search+"%", "%"+options.Search+"%")
// 应用预加载
for _, include := range options.Include {
query = query.Preload(include)
}
// 应用排序
if options.Sort != "" {
order := "ASC"
if options.Order == "desc" || options.Order == "DESC" {
order = "DESC"
}
query = query.Order(options.Sort + " " + order)
} else {
query = query.Order("created_at DESC")
}
// 应用分页
if options.Page > 0 && options.PageSize > 0 {
offset := (options.Page - 1) * options.PageSize
query = query.Offset(offset).Limit(options.PageSize)
}
return entities, query.Find(&entities).Error
}
// 使用基础实现
err := r.BaseRepositoryImpl.List(ctx, &Entity{}, &entities, options)
return entities, err
}
步骤 6:业务方法使用辅助方法
使用 FindOne:
func (r *GormExampleRepository) GetByCode(ctx context.Context, code string) (*Entity, error) {
var entity Entity
err := r.FindOne(ctx, &entity, "code = ?", code)
if err != nil {
return nil, err
}
return &entity, nil
}
使用 FindWhere:
func (r *GormExampleRepository) GetByStatus(ctx context.Context, status string) ([]Entity, error) {
var entities []Entity
err := r.FindWhere(ctx, &entities, "status = ?", status)
return entities, err
}
使用 CountWhere:
func (r *GormExampleRepository) CountByStatus(ctx context.Context, status string) (int64, error) {
return r.CountWhere(ctx, &Entity{}, "status = ?", status)
}
使用 ExistsWhere:
func (r *GormExampleRepository) ExistsByCode(ctx context.Context, code string) (bool, error) {
return r.ExistsWhere(ctx, &Entity{}, "code = ?", code)
}
步骤 7:复杂查询仍使用 GetDB
对于复杂查询,继续使用 r.GetDB(ctx) 来获取数据库连接:
func (r *GormExampleRepository) ComplexQuery(ctx context.Context, params QueryParams) ([]Entity, error) {
var entities []Entity
query := r.GetDB(ctx).Model(&Entity{})
// 添加复杂的查询逻辑
if params.Status != "" {
query = query.Where("status = ?", params.Status)
}
if params.DateRange != nil {
query = query.Where("created_at BETWEEN ? AND ?", params.DateRange.Start, params.DateRange.End)
}
// 连接查询
query = query.Joins("LEFT JOIN related_table ON entities.related_id = related_table.id").
Where("related_table.active = ?", true)
return entities, query.Find(&entities).Error
}
BaseRepositoryImpl 提供的方法
核心方法
GetDB(ctx)- 获取数据库连接(自动支持事务)GetLogger()- 获取日志记录器WithTx(tx)- 创建事务版本的Repository
基础 CRUD
Create(ctx, entity)- 创建实体GetByID(ctx, id, entity)- 根据ID获取Update(ctx, entity)- 更新实体Delete(ctx, id, entity)- 删除实体Exists(ctx, id, entity)- 检查存在
批量操作
CreateBatch(ctx, entities)- 批量创建GetByIDs(ctx, ids, entities)- 批量获取UpdateBatch(ctx, entities)- 批量更新DeleteBatch(ctx, ids, entity)- 批量删除
查询方法
List(ctx, entity, entities, options)- 列表查询Count(ctx, entity, options)- 计数查询FindWhere(ctx, entities, condition, args...)- 条件查询FindOne(ctx, entity, condition, args...)- 单个查询CountWhere(ctx, entity, condition, args...)- 条件计数ExistsWhere(ctx, entity, condition, args...)- 条件存在
软删除
SoftDelete(ctx, id, entity)- 软删除Restore(ctx, id, entity)- 恢复
事务辅助
ExecuteInTransaction(ctx, fn)- 执行事务IsInTransaction(ctx)- 检查事务状态
优势
- 统一事务处理:所有Repository自动支持事务
- 减少代码重复:移除重复的getDB方法和基础CRUD实现
- 提高可维护性:统一的事务逻辑在一个地方维护
- 类型安全:编译时检查,减少运行时错误
- 更清晰的职责:Repository专注于业务逻辑,基础功能由BaseRepository提供
- 完整的接口支持:自动实现Repository[T]和BaseRepository的所有方法
迁移检查清单
- 修改结构体定义,嵌入 BaseRepositoryImpl
- 更新构造函数
- 删除 getDB 方法
- 实现 Repository[T] 接口的所有方法
- 实现 BaseRepository 接口的所有方法
- 使用辅助方法替换重复的查询逻辑
- 为特殊需求重写搜索逻辑
- 运行测试确保功能正常
- 更新相关文档
注意事项
- 方法参数:BaseRepositoryImpl的方法使用
interface{},需要传递指针 - 搜索逻辑:默认搜索逻辑可能不适合所有实体,需要重写
- 预加载:使用ListOptions的Include字段或直接调用GetDB()
- 事务支持:所有方法自动支持事务,无需额外处理
- 日志记录:使用GetLogger()而不是直接访问logger字段