372 lines
		
	
	
		
			11 KiB
		
	
	
	
		
			Markdown
		
	
	
	
	
	
		
		
			
		
	
	
			372 lines
		
	
	
		
			11 KiB
		
	
	
	
		
			Markdown
		
	
	
	
	
	
|  | # 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字段  |