首页 > 解决方案 > AutoMapper 覆盖递归类型

问题描述

我有一个看起来像这样的 Dto:

class TypeDto
{    
    int Id {get; set;}
    string Name {get; set;}
    string DisplayName {get; set;}
    IEnumerable<TypeDto> Children {get; set;}
}

现在我需要从两个不同的来源映射到它。那是因为其中一个包含Name,另一个包含DisplayName。所以类型:

class Type1
{
    int Id {get; set;}
    string Name {get; set;}
    IEnumerable<Type1> Children {get; set;}
}

class Type2
{
    int Id {get; set;}
    string DisplayName {get; set;}
    IEnumerable<Type2> Nested {get; set;}
}

Children注意/Nested可枚举中的名称差异。

现在对于地图我会做:

config.CreateMap<Type1, TypeDto>();

config.CreateMap<Type2, TypeDto>()
    .ForMember(dest => dest.Children, opts => opts.MapFrom(src => src.Nested));

var dto = _mapper.Map<TypeDto>(type1Instance);

_mapper.Map(type2Instance, dto);

第一张地图按预期工作,递归地映射孩子,填充IdandName字段并在任何地方留下DisplayNameequal null。然而,第二个映射DisplayName正确地填充了根对象,但随后在其子对象中,它使该Name字段无效。例如:

var type1Instance = new Type1 
{ 
    Id = 1, 
    Name = "root", 
    Children = new[] { new Type1 
        {
            Id = 2,
            Name = "child"
        }}
};

var type2Instance = new Type2 
{ 
    Id = 1, 
    DisplayName = "Root", 
    Children = new[] { new Type2
        {
            Id = 2,
            DisplayName = "Child"
        }}
};

映射以下实例后,结果的字段设置为:

Id = 1,
Name = "root",
DisplayName = "Root",
Children = { TypeDto { Id = 2, Name = null, DisplayName = "Child", Children = null } }

所以孩子的Name无效,这不是我想要的。我希望它是"child",显然。我应该如何配置映射器以获得想要的行为?

我无法更改Type1orType2类,它们来自外部 API。

AutoMapper 的版本是 6.2.1,.NET Framework 4.5.1。

标签: c#.netautomapperautomapper-6

解决方案


这是一种可能的解决方案:

config.CreateMap<Type2, TypeDto>()
        .ForMember(dest => dest.Children, opts => opts.Ignore())
        .AfterMap((d,e) => AddNestedChildren(d, e));

private void AddNestedChildren(Type2 type, TypeDto dto)
{
    foreach (var child in type.Nested)
    {
        var childDto = dto.Children.SingleOrDefault(c => c.Id == child.Id);
        // keep old properties
        Mapper.Map(child, childDto);
    }
}

如评论中所述,默认情况下集合无效。我可以为您的问题找到的一种解决方案是使用AfterMap,以便手动循环遍历子集/嵌套集合,找到另一个集合的相应子集(通过 Id 或您发现相关的任何其他属性),然后手动映射它。

我对这个问题的回答基本上使用了相同的想法。


推荐阅读