Repository
只有这一层碰 GORM。 十个方法按需取用,签名照抄:
go
var ErrXxxNotFound = errors.New("repository: Xxx 不存在")
type XxxRepository struct{ db *gorm.DB }
func NewXxxRepository(db *gorm.DB) *XxxRepository { return &XxxRepository{db: db} }
func (r *XxxRepository) SelectByID(ctx context.Context, id int64) (*model.SysXxx, error)
func (r *XxxRepository) SelectByIDs(ctx context.Context, ids []int64) ([]*model.SysXxx, error)
func (r *XxxRepository) SelectPageList(ctx, q, page) (pkgrepo.PageResult[*model.SysXxx], error)
func (r *XxxRepository) SelectList(ctx, q, limit int) ([]*model.SysXxx, error)
func (r *XxxRepository) Insert(ctx context.Context, e *model.SysXxx) error
func (r *XxxRepository) UpdateByID(ctx, id int64, columns map[string]any) (int64, error)
func (r *XxxRepository) DeleteByIDs(ctx context.Context, ids []int64) (int64, error)
func (r *XxxRepository) ExistsByYyy(ctx, val string, excludeID int64) (bool, error)六条硬规则
① 查询条件抽成独立函数,分页与导出共用
go
// applyXxxQuery 应用查询条件。分页与导出两条路径必须共用它,否则过滤逻辑改一处漏一处。
func applyXxxQuery(db *gorm.DB, q bo.SysXxxQueryBo) *gorm.DB {
if q.Name != "" { // eqIfText/likeIfText:空串不筛
db = db.Where("name LIKE ?", "%"+escapeLike(q.Name)+"%")
}
if q.Status != "" {
db = db.Where("status = ?", q.Status)
}
// 两端须同时给出:只给一端就筛会让前端清空半个日期框时结果突变。
if q.BeginTime != "" && q.EndTime != "" {
db = db.Where("create_time BETWEEN ? AND ?", q.BeginTime, q.EndTime)
}
return db
}escapeLike 已在 internal/system/repository/config_repository.go 定义, repository 同包共用,别重复定义(同 parseIDs 的约束)。它把 LIKE 元字符转义成字面量——不转义的话搜 % 会命中全表、_ 会变成任意单字符通配。反斜杠排最前,避免重复转义。
② Model() 不能省
del_flag 过滤由 LogicDelete 挂在字段类型上,须先解析出实体 schema 才生效。Count、SelectList、SelectPageList 全都要带。
③ 默认排序只在调用方未指定时兜底
go
// 不能无条件追加:GORM 合并排序子句时先注册的排在前,主键唯一会让后来的排序列失效。
if !page.HasOrder() {
db = db.Order("xxx_id")
}导出路径没有「调用方另指定排序」一说, 固定 db.Order("xxx_id")。
④ 更新走 map[string]any,不走 struct
Updates(struct) 跳过零值,会让「清空备注 / 白名单」写不进库。
⑤ 更新列里不带审计字段
update_by / update_time 由 pkg/repository 的回调自动补。插入同理,create_* 全由回调注入, 不要手填。
⑥ 分页统一走 pkgrepo.SelectPage
别手写 COUNT + LIMIT。ctx 预先通过 WithContext 绑到 db 上,SelectPage 本身不收 ctx:
go
db := applyXxxQuery(r.db.WithContext(ctx).Model(&model.SysXxx{}), q)
if !page.HasOrder() { db = db.Order("xxx_id") }
var rows []*model.SysXxx
return pkgrepo.SelectPage(db, page, &rows)另一个变体 SelectPageCtx(ctx, db, q, dest) 等价,自动补 WithContext。