# 3.4 数据访问层(repository) :::tip 概述 仓储层做一件事:给 service 一个安全的数据库入口。**铁律:禁止裸用 `*gorm.DB`**——统一经 `repository.NewXxxRepo().Ctx(ctx)` 访问,软删过滤与租户隔离自动注入。 ::: ## 标准结构 ```go // internal/repository/example.go package repository import ( "context" "gorm.io/gorm" ) // ExampleRepo 案例演示仓储 type ExampleRepo struct { Base } // NewExampleRepo 构造案例演示仓储(表名 = gin_ + 模块名) func NewExampleRepo() *ExampleRepo { return &ExampleRepo{Base: NewBase("gin_example")} } // Ctx 带 ctx 的查询入口 func (r *ExampleRepo) Ctx(ctx context.Context) *gorm.DB { return r.Base.Ctx(ctx) } ``` 就这么短——结构、构造、Ctx 三段是每个仓储的固定模板,自定义查询方法按需追加在同文件内。关联表(user_role / role_menu)同样建仓储。 ## Base 提供的能力 `Ctx(ctx)` 返回的 `*gorm.DB` 已自动注入: | 注入项 | 条件 | |---|---| | `del_flag = 0` | 所有表——已软删行对查询不可见 | | `tenant_id IN (0, 自身租户)` | 仅租户白名单表且当前身份非平台级(超管)时 | Base 附带的便捷方法: ```go // 软删除(业务删除统一入口,UPDATE del_flag=1) repo.SoftDelete(ctx, "id", id) repo.SoftDeleteByID(ctx, id) // 存在性判断(软删/租户已过滤) ok, err := repo.ExistsByCond(ctx, "name", name) ``` ## GORM 查询写法要点 | 场景 | 写法 | |---|---| | 等值条件 | `.Where("col = ?", v)` | | 非等值 | `.Where("id <> ?", id)` | | IN 条件 | `.Where("col IN ?", slice)` | | LIKE | `.Where(col+" LIKE ?", "%"+pat+"%")` | | 指定列 | `.Select("a,b")` | | 单行读 map | `.Take(&one)`(one 为 `map[string]any`,判空用 `gorm.ErrRecordNotFound`) | | 多行读 | `.Find(&rows)`(`[]map[string]any` 或 `*[]*T`) | | 计数 | `.Count(&n)`(n 为 int64) | | map 插入 | `.Create(&d)`(d 为 `map[string]any`) | | map 更新 | `.Where(..).Updates(d)` | | 分页 | `.Offset((p-1)*size).Limit(size).Find(&list)` | | 排序 | `.Order("sort, id")` | | 结构体扫描 | Find 直接扫结构体(无 gorm 标签时按字段名蛇形映射;非列字段加 `gorm:"-"`) | ## Raw 入口(受限场景) ```go repo.Raw(ctx) // 不注入软删/租户 Scope ``` `Raw()` 仅限**导入、字典管理、登录校验**等明确场景使用——已软删行会进入结果集、跨租户数据可见,条件完整性由使用者自行保证。常规业务查询一律走 `Ctx`。 ## 事务 ```go // db.WithTrans:事务内所有 Ctx 查询自动复用事务连接 err := db.WithTrans(ctx, func(ctx context.Context) error { if err := repoA.Ctx(ctx).Create(&d1).Error; err != nil { return err // 返回错误自动回滚 } return repoB.Ctx(ctx).Create(&d2).Error }) ``` 事务内务必使用回调入参的 ctx(而非外层 ctx),否则拿不到事务连接。 ## 编写检查清单 - [ ] 表名 `gin_` 前缀 + 模块名 - [ ] 只有 Ctx / Raw 两个查询入口,无裸 `*gorm.DB` 字段外泄 - [ ] 删除走 SoftDelete 系列,不写物理 DELETE - [ ] Raw 使用处有注释说明场景正当性 ## 下一步 → [3.5 业务层开发(service)](/zh/guide/service.html)