AutoMapper嵌套映射传递父类信息时遇Context.Items错误求助
问题:AutoMapper嵌套映射传递父类属性时触发Context.Items错误
尝试实现AutoMapper嵌套映射,需要将父类ClassB的Type属性信息传递给子类ClassC的转换器,但映射时触发错误:
Context.Items are only available when using a Map overload that takes Action! Consider using Context.TryGetItems instead.
现有类及DTO结构
public class ClassA { public string Name { get; set; } public List<ClassB> Children { get; set; } } public class ClassB { public int Type { get; set; } public ClassC Value { get; set; } public List<ClassC> AltValues { get; set; } } public class ClassC { public string Name { get; set; } } public class ClassADto { public string Name { get; set; } public List<ClassB> Children { get; set; } } public class ClassBDto { public int Type { get; set; } public ClassCDto Value { get; set; } public List<ClassCDto> AltValues { get; set; } } public class ClassCDto { public string Name { get; set; } }
映射配置
public class MyProfile : Profile { // 转换器已在ServiceCollection中注册 public MyProfile(IValueConverter<string, string> valueConverter) { this.CreateMap<ClassA, ClassADto>().ReverseMap(); this.CreateMap<ClassB, ClassBDto>() .BeforeMap((source, destination, context) => { if (context.TryGetItems(out var items)) { items["ClassBDto"] = source; } }) .ReverseMap(); this.CreateMap<ClassC, ClassCDto>(); this.CreateMap<ClassCDto, ClassC>() .ForMember(field => field.Name, opt => opt.ConvertUsing(valueConverter)); } }
转换器代码
public class MyValueConverter : IValueConverter<string, string> { private readonly IDateParser dateParser; public MyValueConverter(IDateParser parser) { this.parser = parser; } public string Convert(string sourceMember, ResolutionContext context) { if (/* 此处需要检查父类ClassBDto的Type属性 */) { if (this.dateParser.TryParse(sourceMember, out var dt)) { if (dt < SqlDateTime.MinValue.Value) { return string.Empty; } return dt.ToString("O"); } } return sourceMember; } }
调试时对ResolutionContext变量打了断点,触发了上述错误,请问哪里操作有误?
问题原因与修正方案
错误根源
- 上下文传递不完整:原配置仅在正向映射(
ClassB→ClassBDto)时存入父类实例,但反向映射(ClassBDto→ClassB)时未将父类的Type传入上下文,导致转换器无法获取所需值。 - 映射调用方式错误:如果调用
Map方法时未使用带Action<IMappingOperationOptions>参数的重载,AutoMapper不会初始化Items集合,触发错误提示。 - 上下文存储冗余:存入整个
ClassB实例没必要,直接存储Type属性更高效。
修正步骤
1. 完善映射配置的上下文传递
在ClassB与ClassBDto的双向映射中,都添加BeforeMap逻辑,将父类的Type存入上下文:
public class MyProfile : Profile { public MyProfile(IValueConverter<string, string> valueConverter) { this.CreateMap<ClassA, ClassADto>().ReverseMap(); this.CreateMap<ClassB, ClassBDto>() .BeforeMap((source, destination, context) => { if (context.TryGetItems(out var items)) { items["ParentType"] = source.Type; // 直接存储Type值 } }) .ReverseMap() .BeforeMap((source, destination, context) => { if (context.TryGetItems(out var items)) { items["ParentType"] = source.Type; // 反向映射时同样存入Type } }); this.CreateMap<ClassC, ClassCDto>(); this.CreateMap<ClassCDto, ClassC>() .ForMember(field => field.Name, opt => opt.ConvertUsing(valueConverter)); } }
2. 修正转换器的上下文获取逻辑
在转换器中用TryGetItems安全获取Type值,并添加类型校验:
public class MyValueConverter : IValueConverter<string, string> { private readonly IDateParser dateParser; public MyValueConverter(IDateParser parser) { this.dateParser = parser; } public string Convert(string sourceMember, ResolutionContext context) { // 安全获取上下文存储的ParentType if (context.TryGetItems(out var items) && items.TryGetValue("ParentType", out var parentTypeObj) && parentTypeObj is int parentType) { // 替换为你的业务判断条件,比如parentType == 1 if (parentType == 1 && this.dateParser.TryParse(sourceMember, out var dt)) { if (dt < SqlDateTime.MinValue.Value) { return string.Empty; } return dt.ToString("O"); } } return sourceMember; } }
3. 使用正确的映射调用重载
调用Map方法时,必须传入Action<IMappingOperationOptions>参数(哪怕是空实现),确保上下文Items可用:
// 正向映射示例 var classB = new ClassB { Type = 1, Value = new ClassC { Name = "2024-01-01" } }; var dto = mapper.Map<ClassBDto>(classB, opt => { }); // 反向映射示例 var original = mapper.Map<ClassB>(dto, opt => { });
内容的提问来源于stack exchange,提问作者Yulian Dimitrov
相关产品推荐
相关产品推荐

