Automapper嵌套映射

9

我已经阅读了嵌套映射的wiki页面,但似乎不支持多层嵌套。我已经创建了以下地图并定义了类。

AutoMapper.Mapper.CreateMap<Address, AddressDTO>();
AutoMapper.Mapper.CreateMap<MatchCompanyRequest, MatchCompanyRequestDTO>();

public class MatchCompanyRequest
{
    Address Address {get;set;}
}

public class MatchCompanyRequestDTO
{
    public CompanyInformationDTO {get;set;}
}

public class CompanyInformationDTO {get;set;}
{
    public string CompanyName {get;set;}
    public AddressDTO Address {get;set;}
}

但是以下代码...
// works
matchCompanyRequestDTO.companyInformationDTO.Address =
    AutoMapper.Mapper.Map<Address, AddressDTO>(matchCompanyRequest.Address);

// fails
matchCompanyRequestDTO =
    AutoMapper.Mapper
        .Map<MatchCompanyRequest, MatchCompanyRequestDTO>(matchCompanyRequest);

这种深层嵌套是否有效,还是我的配置不正确?或者这种嵌套尚未得到支持?
--编辑
对于有兴趣的人,我无法控制DTOs。
3个回答

6
它缺少从地址映射到CompanyInformationDTO的映射,因为这些对象处于同一嵌套级别。
该映射是为MatchCompanyRequest -> MatchCompanyRequestDTO创建的,但它无法确定是否可以将Address映射到CompanyInformationDTO
因此,您的MatchCompanyRequestDTO实际上可以与您的CompanyInformationDTO具有相同的声明。
public class MatchCompanyRequestDTO
{
    public string CompanyName {get;set;}
    public AddressDTO Address {get;set;}
}

如果您想使用自动映射,那么这当然会影响您。您仍然可以手动配置地图,但似乎应该修复DTOs,无论如何,让我们尝试一下:

public class CustomResolver : ValueResolver<Address, CompanyInformationDTO>
{
    protected override CompanyInformationDTO ResolveCore(Address source)
    {
        return new CompanyInformationDTO() { Address = Mapper.Map<Address, AddressDTO>(source) };
    }
}
// ...

AutoMapper.Mapper.CreateMap<MatchCompanyRequest, MatchCompanyRequestDTO>()
    .ForMember(dest => dest.companyInformationDTO, opt => opt.ResolveUsing<CustomResolver>().FromMember(src => src.Address)); // here we are telling to use our custom resolver that converts Address into CompanyInformationDTO

如果您未使用静态的 Mapper 实例,那么像这样的东西将如何配置? - dougajmcdonald
那么你只需要使用你的实例而不是 AutoMapper.Mapper 吗?我不太确定 - 已经好几年没用 AutoMapper 了... - Bartosz
是的,现在最佳实践是创建一个配置文件并将其馈送到配置中,以便您可以进行 DI 而不使用静态实例。我很好奇,因为我认为这是一种常见的解决方案,想知道它如何符合当前的最佳实践。 - dougajmcdonald
但是为什么会有所不同呢?您在注入的实例上调用CreateMap,其余部分保持不变... - Bartosz
你不应该在注入的实例上调用 CreateMap,而是创建一个配置文件并在其中调用 CreateMap,因为它从 Profile 继承。在解析器中,你无法访问注入的实例。 - dougajmcdonald

5
重要的是你定义导航的深度,以防止堆栈溢出问题。想象一下这种可能性:
你有两个实体“用户”和“通知”在NxN模型中(并且你有DTO对象来表示它),当你使用自动映射器而没有在映射器表达式中设置“MaxDepth”时,“休斯顿,我们有一个问题” :).
以下代码展示了解决此问题的方法,适用于所有映射器。如果你想,可以为每个映射器定义。像这个问题这样 解决方案1(全局定义)
public class AutoMapperConfig
{
    public static void RegisterMappings()
    {
        Mapper.Initialize(mapperConfiguration =>
        {
            mapperConfiguration.AddProfile<DomainModelToYourDTOsMappingProfile>();
            mapperConfiguration.AddProfile<YourDTOsToDomainModelMappingProfile>();
            mapperConfiguration.AllowNullCollections = true;
            mapperConfiguration.ForAllMaps(
                (mapType, mapperExpression) => {
                    mapperExpression.MaxDepth(1);
                });
        }
    }

解决方案2(针对每个Mapper)

 public class AutoMapperConfig
 {
     public static void RegisterMappings()
     {
         Mapper.CreateMap<User, DTOsModel>()
               .MaxDepth(1);
     }
 }

2
这不是对OP的正确答案,但这是非常好的信息。谢谢! - Mathter
谢谢您,@Mathter! - Rodrigo Couto

0
请考虑以下内容:
public class MatchCompanyRequest
{
    Address Address {get;set;}
}

public class MatchCompanyRequestDTO
{
    public string Name {get;set;}
    public AddressDTO Address {get;set;}
}

public class AddressDTO
{
    ....
}

你的DTO对象需要与领域对象具有相同的结构,才能使AutoMapper中的默认映射约定起作用。 看这个:https://github.com/AutoMapper/AutoMapper/wiki/Projection 它会为你解释投影,你可以自定义它以按你想要的方式工作。

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接