如何通过AutoMapper利用父类TimeZoneInfo映射DateTime与DateTimeOffset
解决AutoMapper中子对象借助父对象属性完成类型转换的问题
要完成VisitingHoursDTO的Open/Close(DateTime类型)到VisitingHours的Open/Close(DateTimeOffset类型)的映射,核心是在转换时获取父对象(LocationDTO/Location)的TimeZoneInfo,以下是两种可行方案:
注:根据业务逻辑推测,
LocationDTO中的VisitingHours属性应为IEnumerable<VisitingHoursDTO>(原类定义可能存在笔误),以下方案基于此合理假设编写。
方案一:在父级映射中直接处理子集合转换
这种方式逻辑集中、可读性强,直接在父对象的映射配置中处理子集合的转换逻辑:
CreateMap<Location, LocationDTO>() .ReverseMap() .ForMember(dest => dest.VisitingHours, opt => opt.MapFrom(src => src.VisitingHours.Select(vhDto => new VisitingHours { Open = new DateTimeOffset(vhDto.Open, src.TimeZoneInfo.GetUtcOffset(vhDto.Open)), Close = new DateTimeOffset(vhDto.Close, src.TimeZoneInfo.GetUtcOffset(vhDto.Close)) }) )); // 保留基础的VisitingHours双向映射(父级映射已覆盖反向的集合处理) CreateMap<VisitingHours, VisitingHoursDTO>().ReverseMap();
方案二:在子对象映射中通过ResolutionContext获取父级属性
如果希望子对象的映射逻辑独立,可以利用AutoMapper的ResolutionContext访问父级对象的TimeZoneInfo,但需确保子对象始终在父级映射的上下文下执行:
CreateMap<Location, LocationDTO>().ReverseMap(); CreateMap<VisitingHoursDTO, VisitingHours>() .ForMember(dest => dest.Open, opt => opt.MapFrom((src, _, __, context) => { var parentLocation = context.Parent.SourceValue as LocationDTO; if (parentLocation?.TimeZoneInfo == null) throw new InvalidOperationException("无法获取父级Location的TimeZoneInfo"); return new DateTimeOffset(src.Open, parentLocation.TimeZoneInfo.GetUtcOffset(src.Open)); })) .ForMember(dest => dest.Close, opt => opt.MapFrom((src, _, __, context) => { var parentLocation = context.Parent.SourceValue as LocationDTO; if (parentLocation?.TimeZoneInfo == null) throw new InvalidOperationException("无法获取父级Location的TimeZoneInfo"); return new DateTimeOffset(src.Close, parentLocation.TimeZoneInfo.GetUtcOffset(src.Close)); })) .ReverseMap();
方案对比
- 方案一:逻辑集中,不依赖上下文,避免潜在的空值风险,适合简单的父子映射场景;
- 方案二:映射职责分离,子对象的转换逻辑独立,但需要依赖父级映射的上下文,若单独映射
VisitingHoursDTO会抛出异常。
内容的提问来源于stack exchange,提问作者niroice
相关产品推荐
相关产品推荐

