跳到主要内容
版本:Next

DTO与实体映射配置

本文档引用的文件

目录

  1. 简介
  2. 核心映射配置
  3. 正向映射:实体到DTO
  4. 反向映射:DTO到实体
  5. 高级映射特性
  6. 分页结果的自动转换支持
  7. 敏感字段安全性处理
  8. 映射错误调试方法
  9. 最佳实践建议
  10. 结论

简介

本文档详细说明了MyEntityNameAutoMapperProfile中定义的AutoMapper配置规则,涵盖从MyEntityName实体到MyEntityNameDto的正向映射,以及从MyEntityNameCreateOrUpdateDtoBaseMyEntityName的反向映射。同时阐述了字段忽略、自定义转换、条件映射等高级特性的使用场景与实现方式,并解释如何确保审计信息等敏感字段的安全性。

核心映射配置

MyEntityNameAutoMapperProfile类继承自AutoMapper.Profile,在构造函数中通过CreateMap<TSource, TDestination>方法定义了类型之间的映射关系。该配置支持ABP框架的扩展属性(Extra Properties)和并发控制戳(Concurrency Stamp),确保数据完整性与可扩展性。

Section sources

正向映射:实体到DTO

正向映射定义了从领域实体MyEntityName到数据传输对象MyEntityNameDto的转换规则。此映射通过CreateMap<MyEntityName, MyEntityNameDto>建立,并设置MemberList.None以允许映射所有公共成员。

映射过程中启用了MapExtraProperties选项,参数为MappingPropertyDefinitionChecks.None,表示在映射时包含ABP的扩展属性(如动态属性),且不进行属性定义检查,提升灵活性。

映射字段说明

  • Code: 编号字段,直接映射
  • Name: 名称字段,直接映射
  • Sort: 排序字段,直接映射
  • Remark: 备注字段,直接映射
  • IsDisabled: 是否禁用状态,可为空布尔值
  • ConcurrencyStamp: 并发控制戳,用于乐观锁机制

Diagram sources

Section sources

反向映射:DTO到实体

反向映射通过基类MyEntityNameCreateOrUpdateDtoBase实现,该基类被MyEntityNameCreateDtoMyEntityNameUpdateDto继承。虽然当前配置未显式定义反向映射,但可通过扩展CreateMap添加:

CreateMap<MyEntityNameCreateOrUpdateDtoBase, MyEntityName>()
.ForMember(dest => dest.Id, opt => opt.Ignore()) // 创建时不映射Id
.ForMember(dest => dest.CreationTime, opt => opt.Ignore())
.ForMember(dest => dest.CreatorId, opt => opt.Ignore())
.ForMember(dest => dest.LastModificationTime, opt => opt.Condition(src => src.Id != default))
.ForMember(dest => dest.LastModifierId, opt => opt.Condition(src => src.Id != default));

此类映射确保:

  • 新建实体时忽略Id、创建时间与创建人
  • 更新时仅当Id存在时才更新修改时间与修改人

Section sources

高级映射特性

字段忽略(Ignore)

使用.ForMember(..., opt => opt.Ignore())可排除特定字段的映射。常用于:

  • 实体生成字段(如IdCreationTime
  • 只读属性
  • 敏感信息(如密码、密钥)

自定义转换(Using)

通过.ConvertUsing<ConverterType>().Using()指定自定义转换逻辑,适用于:

  • 枚举与字符串互转
  • 时间格式化
  • 加密/解密字段

条件映射(Condition)

使用.Condition()定义映射前提,例如:

.ForMember(dest => dest.LastModifierId, opt => opt.Condition(src => src.Id != default))

确保仅在更新操作时设置修改人信息。

Section sources

分页结果的自动转换支持

ABP框架中的PagedResultDto<T>可自动与IQueryable<T>结合使用。当MyEntityNameDto完成正确映射后,可通过以下方式实现分页转换:

var query = await _repository.GetQueryableAsync();
var totalCount = await query.CountAsync();
var entities = await query.PageBy(input).ToListAsync();
var dtos = ObjectMapper.Map<List<MyEntityName>, List<MyEntityNameDto>>(entities);

return new PagedResultDto<MyEntityNameDto>(totalCount, dtos);

此模式无需额外配置即可实现分页结果的自动封装与映射。

Section sources

敏感字段安全性处理

为保护审计字段(如创建/修改时间、用户ID)不被客户端篡改,应采取以下措施:

  1. 映射时忽略写入:在DTO到实体的映射中,使用Ignore()排除CreationTimeCreatorId等字段
  2. 服务层赋值:在应用服务中通过CurrentUserClock自动填充审计信息
  3. 验证并发戳:利用ConcurrencyStamp防止并发修改冲突

Diagram sources

映射错误调试方法

常见错误类型

  • Missing Type Map Configuration: 未定义映射关系
  • Unmapped Members: 存在未映射的成员
  • Type Mismatch: 类型不匹配导致转换失败

调试步骤

  1. 启用详细异常:在开发环境中开启Mapper.AssertConfigurationIsValid()
  2. 检查未映射成员:使用AssertConfigurationIsValid()验证配置完整性
  3. 日志记录:记录源对象与目标对象结构
  4. 单元测试:编写映射测试用例验证双向转换

Diagram sources

最佳实践建议

  1. 分离映射配置:复杂系统中将不同模块的映射配置拆分为多个Profile类
  2. 统一命名规范:保持实体与DTO命名一致性,便于识别
  3. 避免循环引用:DTO设计时注意防止导航属性导致的序列化问题
  4. 性能优化:对高频调用接口使用ProjectTo<T>()直接在数据库端投影
  5. 版本兼容:DTO变更时考虑向后兼容性,避免破坏现有API

结论

MyEntityNameAutoMapperProfile通过简洁的配置实现了实体与DTO之间的高效转换,结合ABP框架特性保障了扩展性与安全性。合理运用字段忽略、条件映射等高级功能,可有效控制数据流向,保护敏感信息。建议在开发过程中持续验证映射配置,并通过单元测试确保转换逻辑的正确性。