You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

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变量打了断点,触发了上述错误,请问哪里操作有误?


问题原因与修正方案

错误根源

  1. 上下文传递不完整:原配置仅在正向映射(ClassB→ClassBDto)时存入父类实例,但反向映射(ClassBDto→ClassB)时未将父类的Type传入上下文,导致转换器无法获取所需值。
  2. 映射调用方式错误:如果调用Map方法时未使用带Action<IMappingOperationOptions>参数的重载,AutoMapper不会初始化Items集合,触发错误提示。
  3. 上下文存储冗余:存入整个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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.29 16:02:02