# Repository 迁移指南 ## 从传统模式迁移到 BaseRepositoryImpl 模式 ### 步骤 1:修改结构体定义 **之前:** ```go type GormExampleRepository struct { db *gorm.DB logger *zap.Logger } ``` **之后:** ```go type GormExampleRepository struct { *database.BaseRepositoryImpl // 嵌入基础Repository实现 } ``` ### 步骤 2:修改构造函数 **之前:** ```go func NewGormExampleRepository(db *gorm.DB, logger *zap.Logger) ExampleRepository { return &GormExampleRepository{ db: db, logger: logger, } } ``` **之后:** ```go func NewGormExampleRepository(db *gorm.DB, logger *zap.Logger) ExampleRepository { return &GormExampleRepository{ BaseRepositoryImpl: database.NewBaseRepositoryImpl(db, logger), } } ``` ### 步骤 3:删除 getDB 方法 **删除这样的代码:** ```go 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 - 之前:** ```go 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 - 之后:** ```go 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 - 之前:** ```go 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 - 之后:** ```go 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 - 之前:** ```go 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 - 之后:** ```go 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:** ```go 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:** ```go 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:** ```go 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:** ```go 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:** ```go 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:** ```go func (r *GormExampleRepository) Exists(ctx context.Context, id string) (bool, error) { return r.BaseRepositoryImpl.Exists(ctx, id, &Entity{}) } ``` **Count:** ```go 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:** ```go 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:** ```go 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:** ```go 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:** ```go 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:** ```go 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:** ```go func (r *GormExampleRepository) CountByStatus(ctx context.Context, status string) (int64, error) { return r.CountWhere(ctx, &Entity{}, "status = ?", status) } ``` **使用 ExistsWhere:** ```go func (r *GormExampleRepository) ExistsByCode(ctx context.Context, code string) (bool, error) { return r.ExistsWhere(ctx, &Entity{}, "code = ?", code) } ``` ### 步骤 7:复杂查询仍使用 GetDB 对于复杂查询,继续使用 `r.GetDB(ctx)` 来获取数据库连接: ```go 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)` - 检查事务状态 ## 优势 1. **统一事务处理**:所有Repository自动支持事务 2. **减少代码重复**:移除重复的getDB方法和基础CRUD实现 3. **提高可维护性**:统一的事务逻辑在一个地方维护 4. **类型安全**:编译时检查,减少运行时错误 5. **更清晰的职责**:Repository专注于业务逻辑,基础功能由BaseRepository提供 6. **完整的接口支持**:自动实现Repository[T]和BaseRepository的所有方法 ## 迁移检查清单 - [ ] 修改结构体定义,嵌入 BaseRepositoryImpl - [ ] 更新构造函数 - [ ] 删除 getDB 方法 - [ ] 实现 Repository[T] 接口的所有方法 - [ ] 实现 BaseRepository 接口的所有方法 - [ ] 使用辅助方法替换重复的查询逻辑 - [ ] 为特殊需求重写搜索逻辑 - [ ] 运行测试确保功能正常 - [ ] 更新相关文档 ## 注意事项 1. **方法参数**:BaseRepositoryImpl的方法使用`interface{}`,需要传递指针 2. **搜索逻辑**:默认搜索逻辑可能不适合所有实体,需要重写 3. **预加载**:使用ListOptions的Include字段或直接调用GetDB() 4. **事务支持**:所有方法自动支持事务,无需额外处理 5. **日志记录**:使用GetLogger()而不是直接访问logger字段