| name | metaframe-active-record-pattern |
|---|---|
| category | engineering |
| description | 活动记录模式 | Code & Engineering |
英文名: Active Record Pattern
分类: 编码实践
作者: Martin Fowler, 2002
复杂度: beginner
成熟度: established
AI 相关: ❌ 否
将数据库行封装并在对象内部实现 CRUD 逻辑的领域对象模式
- 每类一表映射:每个活动记录类直接映射到一张数据库表,无需中间映射层
- 自包含持久化:领域对象拥有自己的 SQL 或查询构建器调用,无需独立的 DAO 或仓储类
- 生命周期回调:在创建、更新、删除事件时自动触发的钩子,使验证和审计等横切关注点驻留在模型上
- 查询方法:类级别查询方法返回预填充对象,将 SQL 封装在友好的领域 API 之后
- 约定优于配置:命名约定(复数表名、id 主键)消除了样板映射配置
- 将类映射到数据库表:每个类属性对应一列,每个实例代表该表中的一行
- 在对象上内嵌持久化方法:直接在领域类上实现 save()、find()、update() 和 delete(),调用方无需直接接触 SQL
- 使用类级别查询方法:暴露 User.findByEmail() 等静态或类方法,将其转换为 SQL SELECT 并返回填充好的对象
- 利用生命周期回调:在类上挂载 before_save、after_create 等回调,以强制验证、时间戳和副作用
- 随代码一起迁移模式变更:将数据库迁移文件版本化并置于模型文件旁,使模式与行为同步演进
['构建以 CRUD 为主、领域逻辑较薄且紧密映射数据库模式的应用', '快速原型或中小型 Web 应用,开发速度优先于架构纯粹性', '希望用单一内聚对象同时充当领域模型和持久化层、无需独立仓储层的团队', '使用约定优于配置框架(如 Rails 或 Laravel)且 Active Record 是惯用方法的应用']
- 对于领域模型与表结构高度一致的直接 CRUD,使用活动记录
- 利用生命周期回调进行验证和自动时间戳管理,而非在服务层重复逻辑
- 依赖框架提供的迁移工具跨环境保持模式与模型同步
- 添加作用域或命名查询方法封装常用过滤条件,而非将裸查询分散在代码库中
- 不要在具有丰富业务规则的复杂领域中使用活动记录——持久化与行为的耦合会成为维护负担
- 不要在生命周期回调中编写业务逻辑,因为这对调用方不可见且难以独立测试
- 不要将活动记录对象作为 DTO 跨服务边界共享,因为这会泄漏持久化细节,导致模式变更意外级联
- 不要让模型积累数百个方法——当模型超出单一职责时,改用服务对象或数据映射器
Sources: SDFrame (Software Design) MetaFrame: 💻 Code & Engineering / 编码与工程