开发中,我们通常把数据模型分为几个部分,探讨下他们具体都有那些作用。
1. Entity(实体)
实体类代表数据库表结构,与数据库表一一对应。
// 例如 User.cs
public class User : BaseEntity
{public string Username { get; set; }public string Password { get; set; }// ...
}
主要特点:
- 代表数据库表的实体类,与数据库表结构一一对应
- 包含数据库字段的完整定义,如主键、外键、索引等
- 通常带有 ORM 相关的特性标注(Table、Column 等)
- 可以包含实体间的导航属性,表示表之间的关系
- 不应该直接暴露给外部接口,因为可能包含敏感信息(如密码)
2. DTO(数据传输对象)
用于在不同层之间传输数据的对象。
// 例如 UserDto.cs
public class UserDto
{public long Id { get; set; }public string Username { get; set; }// 不包含密码等敏感字段
}
主要特点:
- 用于在不同层之间传输数据的对象
- 通常是实体类的精简版,只包含需要传输的字段
- 可以组合多个实体的数据
- 去除了敏感信息,更安全
- 可以添加额外的展示字段,更适合业务需求
3. Request(请求模型)
专门用于接收 API 请求的数据模型。
// 例如 CreateUserRequest.cs
public class CreateUserRequest
{[Required]public string Username { get; set; }[Required]public string Password { get; set; }
}
主要特点:
- 专门用于接收 API 请求的数据模型
- 包含数据验证特性(如 Required、StringLength 等)
- 只包含客户端需要提交的字段
- 可以根据不同的操作(增、删、改)定义不同的请求模型
- 更好地控制客户端可以提交的数据范围
4. Response(响应模型)
统一的 API 响应格式。
// 例如 ApiResponse.cs
public class ApiResponse<T>
{public int Code { get; set; }public string Message { get; set; }public T? Data { get; set; }
}
主要特点:
- 统一的 API 响应格式
- 包含状态码、消息等通用字段
- 可以包装任意类型的响应数据
- 便于统一处理成功/失败的响应
- 有利于前端统一处理响应结果
分层的主要好处
1. 关注点分离
- 每种模型都有其特定的职责
- 不同层级使用不同的模型,避免耦合
2. 安全性
- 实体类中的敏感信息不会直接暴露
- 可以控制客户端能够访问的数据范围
3. 灵活性
- 可以根据不同场景使用不同的模型
- 数据库结构变化时,只需修改实体类
4. 可维护性
- 代码结构清晰,易于理解和维护
- 便于进行单元测试
- 便于处理版本升级和 API 变更
5. 验证和转换
- 请求模型可以进行数据验证
- DTO 可以进行数据转换和组合
实际开发中的数据流向
graph LRA[客户端请求] --> B[Request模型]B --> C[业务处理]C --> D[Entity实体]D --> E[数据库]E --> F[Entity实体]F --> G[DTO转换]G --> H[Response模型]H --> I[客户端响应]
这种模式虽然看起来代码量增加了,但是带来的好处远大于维护成本,特别是在大型项目中更为明显。