2011-10-24 17 views
8

He leído la página wiki de mapeo anidado, pero parece que no me gustan los niveles múltiples de anidamiento. Tengo los siguientes mapas creados y las clases definidas.Correlación anidada de Automapper

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;} 
} 

Pero el siguiente código ...

// works 
matchCompanyRequestDTO.companyInformationDTO.Address = 
    AutoMapper.Mapper.Map<Address, AddressDTO>(matchCompanyRequest.Address); 

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

hace este trabajo de anidación profunda y lo tengo configurado incorrectamente? ¿O este tipo de anidación aún no es compatible?

- Editar

Para todos los interesados, no tengo el control de los dtos.

Respuesta

6

Carece de la asignación de Dirección a CompanyInformationDTO, ya que esos objetos están en el mismo nivel de nido.

El mapa se crea para MatchCompanyRequest ->MatchCompanyRequestDTO, pero es incapaz de averiguar si se puede asignar a AddressCompanyInformationDTO.

Así que su MatchCompanyRequestDTO de hecho, podría tener la misma declaración como su CompanyInformationDTO:

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

Por supuesto, esto sólo le afecta si desea utilizar la asignación automática. Todavía se puede configurar sus mapas de forma manual, pero parece que los dtos deben fijarse en su lugar, vamos a tratar de todos modos:

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 
+0

Cómo sería algo como esto puede configurar si usted no está utilizando la estática ¿Instancia 'Mapper'? – dougajmcdonald

+0

¿Entonces solo usa su instancia en lugar de 'AutoMapper.Mapper'? Realmente no sé, han pasado años desde que utilicé AutoMapper ... – Bartosz

+0

Sí, la mejor práctica en estos días es crear un perfil y alimentarlo en la configuración para que pueda DI y no usar las instancias estáticas. Tengo curiosidad porque veo esto como una solución común y me pregunto cómo encaja con las mejores prácticas actuales. – dougajmcdonald

0

Considere el siguiente lugar:

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

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

public class AddressDTO 
{ 
    .... 
} 

Sus objetos DTO necesita tener el mismo estructura a medida que su dominio se opone a que las convenciones de asignación predeterminadas funcionen en AutoMapper.

Mira esto: https://github.com/AutoMapper/AutoMapper/wiki/Projection Te explicará la proyección, puedes personalizarla para que funcione de la forma que la tienes.

4

Lo importante es definir qué tan profunda es su navegación, para evitar los problemas de stackoverflow. Imagínese esta posibilidad:

Tienes 2 entidades Usuarios y Notificaciones en el modelo de NxN (y tiene dtos objeto para representar eso), cuando el usuario automática asignador sin establecer ProfundidadMáx en que Mapper expresión, "Huston tenemos un problema " :).

El código siguiente muestra una solución para resolver esto para todos los Mappers. Si quieres puedes definirlo para cada mapeador.Like this Question

Solución 1 (Definición Global)

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); 
       }); 
      }); 
     } 
    } 

Solución 2 (Para cada Mapper)

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

No es la respuesta correcta al OP, pero es realmente buena información. ¡Gracias! – Mathter

+0

¡Gracias @Mathter! –