# Repository层规范 ## 概述 Repository 层是数据访问层,封装所有数据库操作。各模块 Repository 继承 `BaseRepository(Model]`,获得通用 CRUD 能力,子类按需添加自定义查询。 :::tip 设计原则 - Repository 只做数据访问原语,不处理 R 封装/序列化/业务逻辑 - 软删除由基类自动处理,子类无需关心 - 查询方法自动跳过 None 值条件 ::: ## BaseRepository 继承 以岗位模块为例,`src/modules/position/repository.py` 完整内容: ```python """modules/system/position 数据访问层。""" from position.models import Position from core.base_repository import BaseRepository class PositionRepository(BaseRepository(Position]): """岗位数据仓库,继承基础仓库获得通用 CRUD 能力""" pass # 模块级单例 position_repo = PositionRepository() ``` :::tip 使用方式 Service 层通过 `repo_cls = PositionRepository` 声明关联的 Repository 类,`BaseService.__init__` 自动实例化。Repository 子类只需声明 `model` 属性即可。 ::: ## 查询方法选择表 | 方法 | 软删过滤 | 自动跳过 None | 适用场景 | |------|---------|--------------|---------| | `get_by_id(id)` | 是 | - | 按 ID 查询单条 | | `get_by_ids(ids)` | 是 | - | 按 ID 列表批量查询 | | `get_one(**filters)` | 是 | 是 | 按等值条件查单条 | | `all(**filters)` | 是 | 是 | 按等值条件查多条 | | `count(**filters)` | 是 | 是 | 统计记录数 | | `exists(obj_id)` | 是 | - | 检查记录是否存在 | | `exists_by_field(field, value, exclude_id)` | 是 | - | 唯一性校验 | | `filter_by(**kwargs)` | 是 | 是 | 等值查询,返回 Query | | `filter(*criterion)` | **否** | - | 原始查询,复杂条件 | | `paginate(page, size, query)` | 是 | - | 分页查询 | :::warning filter 与 filter_by 的区别 - `filter_by(**kwargs)`:等值查询,自动软删过滤,跳过 None 值,返回 Query - `filter(*criterion)`:原始查询,**不自动软删过滤**,用于 `in_`/`!=`/`and_`/区间等复杂条件,需调用方自行追加 `is_delete == 0` ::: ## 常用查询示例 ### 等值查询 ```python # 查询单条:自动软删过滤,跳过 None user = user_repo.get_one(username='admin', status=1) # 查询多条:自动软删过滤 positions = position_repo.all(status=1) # 统计数量 count = position_repo.count(status=1) # 唯一性校验 exists = position_repo.exists_by_field('name', '开发工程师', exclude_id=5) ``` ### 复杂条件查询 ```python # 使用 filter(需自行追加 is_delete 条件) users = user_repo.filter( User.dept_id.in_([1, 2, 3]), User.is_delete == 0 ).all() # 区间查询 articles = article_repo.filter( Article.create_time >= start_date, Article.create_time <= end_date, Article.is_delete == 0 ).all() # 使用 filter_by + 排序 positions = position_repo.filter_by(status=1).order_by( Position.sort.asc() ).all() ``` ### 分页查询 ```python # 自定义 query 分页 query = position_repo.filter_by(status=1).order_by(Position.sort.asc()) items, total = position_repo.paginate(page_no=1, page_size=10, query=query) ``` ## 写操作 ### 创建 ```python # 创建记录(不提交事务,由中间件统一管理) position_repo.create(name='开发工程师', status=1, sort=1) ``` ### 更新 ```python # 按 ID 更新,返回受影响行数 count = position_repo.update(obj_id=1, data={'name': '高级开发工程师', 'sort': 2}) ``` ### 删除 ```python # 软删除,返回实际删除条数 count = position_repo.batch_delete("1,2,3") ``` :::tip 删除的 R 封装 Repository 的 `batch_delete` 只做数据原语,R 响应由 Service 层 `BaseService.delete(handler, ids)` 统一产出。禁止在 Repository 层直接返回 R 对象。 ::: ## 自定义查询方法 子类可添加模块特有的查询方法: ```python class UserRepository(BaseRepository(User]): """用户数据仓库""" def get_by_username(self, username: str): """根据用户名查询""" return self.get_one(username=username) def get_users_by_dept(self, dept_id: int): """查询部门下所有用户""" return self.all(dept_id=dept_id) def get_users_with_role(self, role_id: int): """查询拥有指定角色的用户""" return self.filter( User.is_delete == 0 ).join( UserRole, UserRole.user_id == User.id ).filter( UserRole.role_id == role_id ).all() ``` ## 数据清洗 `create` 和 `update` 方法内置 `_clean_model_data()`,自动将 camelCase 键转为 snake_case,并仅保留模型真实列字段: ```python # 传入 camelCase 键,自动转换 position_repo.create(positionName='开发', status=1) # 内部自动转为 position_name → 查找模型列 → 忽略不存在的字段 ``` ## 总结 Repository 层通过继承 `BaseRepository(Model]` 获得完整的 CRUD 能力。查询方法分两类:等值便捷方法(`get_one`/`get_all`/`filter_by` 等,自动软删过滤)和原始查询出口(`filter`,需自行处理软删)。写操作由 Repository 做数据原语,R 响应由 Service 层统一封装。模块级单例模式避免重复创建实例。