如何使用AutoMapper实现嵌套对象的映射?
问题描述
现有如下实体类与DTO类:
实体与基础DTO
public class MyEntity { public string Name {get; set;} } public class MyEntityDto { public string Name {get;set;} }
聚合类与对应DTO
public class MyAgg { public string SomeProp {get;set;} public MyEntity Entity {get;set;} } public class MyAggDto { public string SomeProp {get;set;} public AggDataDto Data {get;set;} public class AggDataDto { public MyEntityDto Entity {get;set;} } }
映射配置类
public class MyProfile : Profile { public MyProfile() { CreateMap<MyEntity, MyEntityDto>(); CreateMap<MyAgg, MyAggDto>() .ForMember(dest => dest.Data, opt => opt.MapFrom(src => { return new MyAggDto.AggDataDto { /* 我能否在此处注入并使用IMapper,从src.Entity获取MyEntityDto? 我应该用new MyEntityDto(...)创建Dto吗? 还有其他方法吗? */ Entity = ... } })); } }
需要实现MyAgg到MyAggDto的嵌套对象映射,具体是将MyAgg.Entity转换为MyAggDto.Data.Entity(即MyEntityDto)。
解决方案
方法一:利用AutoMapper自动映射嵌套结构
最简洁的方式是给嵌套的AggDataDto添加映射规则,让AutoMapper自动复用已有的MyEntity→MyEntityDto映射:
public class MyProfile : Profile { public MyProfile() { // 基础映射 CreateMap<MyEntity, MyEntityDto>(); // 配置MyAgg到AggDataDto的映射,将MyAgg.Entity映射到AggDataDto.Entity CreateMap<MyAgg, MyAggDto.AggDataDto>() .ForMember(dest => dest.Entity, opt => opt.MapFrom(src => src.Entity)); // 配置MyAgg到MyAggDto的映射,直接将源对象映射到Data属性 CreateMap<MyAgg, MyAggDto>() .ForMember(dest => dest.Data, opt => opt.MapFrom(src => src)); } }
AutoMapper会自动递归处理嵌套映射,无需手动构造对象,维护性最好。
方法二:通过映射上下文获取IMapper实例
如果需要手动构造AggDataDto,可以在ResolveUsing中通过映射上下文(ResolutionContext)获取IMapper实例,复用已有的映射规则:
public class MyProfile : Profile { public MyProfile() { CreateMap<MyEntity, MyEntityDto>(); CreateMap<MyAgg, MyAggDto>() .ForMember(dest => dest.Data, opt => opt.ResolveUsing((src, dest, _, context) => { return new MyAggDto.AggDataDto { // 利用上下文的Mapper实例执行已有映射 Entity = context.Mapper.Map<MyEntityDto>(src.Entity) }; })); } }
这种方式适合需要在构造嵌套对象时添加额外逻辑的场景,比如判断src.Entity是否为null等。
方法三:手动构造DTO(不推荐)
可以手动new MyEntityDto并赋值,但这种方式硬编码属性,一旦MyEntity或MyEntityDto的属性变更,需要同步修改这里的代码,违反DRY原则,仅适合简单场景:
public class MyProfile : Profile { public MyProfile() { CreateMap<MyEntity, MyEntityDto>(); CreateMap<MyAgg, MyAggDto>() .ForMember(dest => dest.Data, opt => opt.MapFrom(src => { return new MyAggDto.AggDataDto { Entity = src.Entity != null ? new MyEntityDto { Name = src.Entity.Name } : null }; })); } }
内容的提问来源于stack exchange,提问作者acmoune
相关产品推荐
相关产品推荐

