2010-01-12 9 views
6

Actualización 1-13-10 He podido encontrar cierto éxito utilizando el siguiente código para la asignación. En esencia, ignoro cualquiera de las propiedades que no tienen un mapeo y luego las mapeo. Agradecería recibir comentarios sobre si estoy o no haciendo esto de la mejor manera posible. Además, no estoy seguro de cómo hacer una prueba unitaria de este mapeo. Tenía la impresión de que el uso de AutoMapper debería ayudar a aliviar la tediosidad de verificar cada propiedad.Excepción de asignación personalizada de Automapper

Aquí está mi nuevo código:

Mapper.CreateMap<MoveEntity, MoveEntityDto>() 
      .ForMember(dest => dest.PrimaryOriginTransferee, opt => opt.Ignore()) 
      .ForMember(dest => dest.PrimaryDestinationTransferee, opt => opt.Ignore()) 
      .ForMember(dest => dest.Customer, opt => opt.Ignore()) 
      .ForMember(dest => dest.DestinationAddress, opt => opt.Ignore()) 
      .ForMember(dest => dest.OriginAddress, opt => opt.Ignore()) 
      .ForMember(dest => dest.Order, opt => opt.Ignore()) 
      .ForMember(dest => dest.Shipment, opt => opt.Ignore()) 
      .ForMember(dest => dest.SourceSystemName, opt => opt.Ignore()); 

     Mapper.CreateMap<ContactEntity, TransfereeEntityDto>(); 
     Mapper.CreateMap<CustomerEntity, CustomerEntityDto>(); 
     Mapper.CreateMap<AddressEntity, AddressEntityDto>(); 
     Mapper.CreateMap<OrderEntity, OrderEntityDto>() 
      .ForMember(dest => dest.OrderForwarding, opt => opt.Ignore()) 
      .ForMember(dest => dest.Forwarder, opt => opt.Ignore()); 
     Mapper.CreateMap<ShipmentEntity, ShipmentEntityDto>() 
      .ForMember(dest => dest.Services, opt => opt.Ignore()); 
     Mapper.CreateMap<ServiceEntity, ServiceEntityDto>() 
      .ForMember(dest => dest.ServiceTypeCode, opt => opt.Ignore()) //TODO: ServiceTypeCode not being mapped, should it? 
      .ForMember(dest => dest.SourceSystemName, opt => opt.MapFrom(src => Enum.GetName(typeof(SourceSystemName), src.SourceSystemName))); 
     Mapper.CreateMap<OrderForwardingEntity, OrderForwardingEntityDto>(); 


     Mapper.AssertConfigurationIsValid(); 


     MoveEntityDto moveEntityDto = Mapper.Map<MoveEntity, MoveEntityDto>(moveEntity); 
     moveEntityDto.PrimaryDestinationTransferee = Mapper.Map<ContactEntity, TransfereeEntityDto>(moveEntity.PrimaryDestinationTransferee); 
     moveEntityDto.PrimaryOriginTransferee = Mapper.Map<ContactEntity, TransfereeEntityDto>(moveEntity.PrimaryOriginTransferee); 
     moveEntityDto.Customer = Mapper.Map<CustomerEntity, CustomerEntityDto>(moveEntity.Customer); 
     moveEntityDto.DestinationAddress = Mapper.Map<AddressEntity, AddressEntityDto>(moveEntity.DestinationAddress); 
     moveEntityDto.OriginAddress = Mapper.Map<AddressEntity, AddressEntityDto>(moveEntity.OriginAddress); 
     moveEntityDto.Order = Mapper.Map<OrderEntity, OrderEntityDto>(moveEntity.Order); 
     moveEntityDto.Order.OrderForwarding = Mapper.Map<OrderForwardingEntity, OrderForwardingEntityDto>(moveEntity.Order.OrderForwarding); 
     //moveEntityDto.Order.Forwarder = Mapper.Map<ForwarderEntity, ForwarderEntityDto>(moveEntity.Order.Forwarder); //Apparently there is no forwarder entity for an Order 
     moveEntityDto.Shipment = Mapper.Map<ShipmentEntity, ShipmentEntityDto>(moveEntity.Shipment); 
     moveEntityDto.Shipment.Services = Mapper.Map<ServiceEntity[], ServiceEntityDto[]>(moveEntity.Shipment.ServiceEntities); 

Post original:

Estoy intentando utilizar AutoMapper por primera vez con el fin de asignar a un objeto de Bussiness a un DTO. Estoy corriendo en temas que no sé cómo solucionar problemas, entre ellos la siguiente excepción:

AutoMapper.AutoMapperMappingException: Tratar de trazar Graebel.SP.BO.MoveEntity a Graebel.SOA.Contracts.DataContracts.SP. MoveEntity. excepción de tipo 'AutoMapper.AutoMapperMappingException' fue arrojado

Aquí está el código AutoMapper que estoy corriendo:

public MoveEntityDto MapMoveEntityToMoveEntityDto(MoveEntity moveEntity) 
    { 
     Mapper.CreateMap<MoveEntity, MoveEntityDto>() 
      .ForMember(dest => dest.PrimaryOriginTransferee, opt => opt.MapFrom(src => src.PrimaryOriginTransferee)) 
      .ForMember(dest => dest.PrimaryDestinationTransferee,opt => opt.MapFrom(src => src.PrimaryDestinationTransferee)) 
      .ForMember(dest => dest.Customer, opt => opt.MapFrom(src => src.Customer)) 
      .ForMember(dest => dest.DestinationAddress, opt => opt.MapFrom(src => src.DestinationAddress)) 
      .ForMember(dest => dest.Order, opt => opt.MapFrom(src => src.Order)) 
      .ForMember(dest => dest.OriginAddress, opt => opt.MapFrom(src => src.OriginAddress)) 
      .ForMember(dest => dest.Shipment, opt => opt.MapFrom(src => src.Shipment)) 
      .ForMember(dest => dest.SourceSystemName, opt => opt.Ignore()); 

     Mapper.AssertConfigurationIsValid(); 
     MoveEntityDto moveEntityDto = Mapper.Map<MoveEntity, MoveEntityDto>(moveEntity); 

     return moveEntityDto; 
    } 

Aquí está la DTO (MoveEntityDto) que yo estoy tratando de mapa:

public class MoveEntityDto 
{  
    public bool IsOrderDetailPageModified { get; set; } 
    public bool IsRoutingPageModified { get; set; } 
    public bool IsServicePageModified { get; set; } 
    public bool IsContentAndContainerPageModified { get; set; } 
    public string FamilyRange { get; set; } 
    public string Office { get; set; } 
    public string ActivityType { get; set; } 
    public string ActivitySubject { get; set; } 
    public string ActivityNote { get; set; } 
    public TransfereeEntity PrimaryOriginTransferee { get; set; } 
    public TransfereeEntity PrimaryDestinationTransferee { get; set; } 
    public CustomerEntity Customer { get; set; } 
    public AddressEntity OriginAddress { get; set; } 
    public AddressEntity DestinationAddress { get; set; } 
    public OrderEntity Order { get; set; } 
    public ShipmentEntity Shipment { get; set; } 
    public string PortalId { get; set; } 
    public string SourceSystemId { get; set; } 
    public EnterpriseEnums.SourceSystemName SourceSystemName { get; set; } 

    public MoveEntity() 
    { 
     PrimaryOriginTransferee = new TransfereeEntity(); 
     PrimaryDestinationTransferee = new TransfereeEntity(); 
     Customer = new CustomerEntity(); 
     OriginAddress = new AddressEntity(); 
     DestinationAddress = new AddressEntity(); 
     Order = new OrderEntity(); 
     Shipment = new ShipmentEntity(); 
    } 

    public bool HasShipment() 
    { 
     if (Shipment.ExternalShipmentId > 0) 
     { 
      return true; 
     } 
     return false; 
    } 
} 

Aquí es el objeto comercial (MoveEntity) que yo estoy tratando de mapa de

public class MoveEntity 
{ 
    public int SourceId { get; set; } 
    public int MoveId { get; set; } 
    public bool IsOrderDetailPageModified { get; set; } // TODO: Internal - Remove from data contract 
    public bool IsRoutingPageModified { get; set; } // TODO: Internal - Remove from data contract 
    public bool IsServicePageModified { get; set; } // TODO: Internal - Remove from data contract 
    public bool IsContentAndContainerPageModified { get; set; } // Rmove from data contract 
    public string FamilyRange { get; set; } // TODO: Is this being used? 
    public string Office { get; set; } 
    public string ActivityType { get; set; } 
    public string ActivitySubject { get; set; } 
    public string ActivityNote { get; set; } 
    public ContactEntity PrimaryOriginTransferee { get; set; } 
    public ContactEntity PrimaryDestinationTransferee { get; set; } 
    public CustomerEntity Customer { get; set; } 
    public AddressEntity OriginAddress { get; set; } 
    public AddressEntity DestinationAddress { get; set; } 
    public OrderEntity Order { get; set; } 
    public ShipmentEntity Shipment { get; set; } 
    public string CreatedBy { get; set; } 
    public DateTime CreatedDate { get; set; } 
    public string ModifiedBy { get; set; } 
    public DateTime ModifiedDate { get; set; } 
    public string SourceSystemId { get; set; } 
    public string SourceSystemName { get; set; } 
    public string Version { get; set; } 
    public string PortalId { get; set; } 

    public MoveEntity() 
    { 
     PrimaryOriginTransferee = new ContactEntity 
     { 
      ContactTypeId = ContactEntity.ContactType.PrimaryOriginationTransferee 
     }; 

     PrimaryDestinationTransferee = new ContactEntity 
     { 
      ContactTypeId = ContactEntity.ContactType.PrimaryDestinationTransferee 
     }; 

     OriginAddress = new AddressEntity 
     { 
      AddressTypeId = AddressEntity.AddressType.Origination 
     }; 

     DestinationAddress = new AddressEntity 
     { 
      AddressTypeId = AddressEntity.AddressType.Destination 
     }; 

     Order = new OrderEntity(); 
     Customer = new CustomerEntity(); 
     Shipment = new ShipmentEntity(); 
    } 

    public bool HasShipment() 
    { 
     if (Shipment.ShipmentId > 0) 
     { 
      return true; 
     } 
     return false; 
    } 
} 

Las propiedades de cada clase casi coinciden perfectamente por su nombre, pero sus tipos son diferentes. Por lo tanto, he intentado realizar una asignación personalizada utilizando la expresión "MapFrom". Sin embargo, AutoMapper no parece poder permitirme apuntar de un tipo de objeto a otro sin quejarse.

También he intentado mapear de propiedad a propiedad, sin suerte. Parecía algo como esto:

.ForMember(dest => dest.PrimaryOriginTransferee.Email, opt => opt.MapFrom(src => src.PrimaryOriginTransferee.Email)) 

Sin embargo, cuando se trata de esto, recibirá el siguiente exeception:

debe resolver al miembro de nivel superior. Nombre del parámetro: lambdaExpression.

He estado descubriendo que la documentación disponible para AutoMapper es difícil de seguir. ¿Puede alguien señalarme en la dirección correcta sobre cómo usar esta utilidad correctamente?

¡Gracias de antemano por cualquier ayuda!

Adam

+0

Texto de la pared O ....: ~ ( –

+2

La próxima vez me aseguraré de que no haya suficiente información. Gracias por su contribución. – letsgetsilly

+0

Lolz :) :) :) :) –

Respuesta

5

Finalmente terminé haciendo que esto funcionara por mi cuenta. El código que terminé usando se publica a continuación. Crear el mapa de objetos en el orden correcto demostró ser importante. Aprendí mucho luchando a través de esto.

He organizado mis asignaciones en un perfil, que no entraré aquí, basta con decir que si puede usar mi ejemplo fuera de una clase que hereda de la clase Perfil de AutoMapper, querrá usar Mapper.CreateMap en lugar de solo crear mapa.

private void CreateMaps() 
    { 

     CreateMap<ContactEntity, TransfereeEntityDto>(); 

     //ContactEntity Mapping 
     CreateMap<ContactEntity, TransfereeEntityDto>(); 

     //CustomerEntity Mapping 
     CreateMap<CustomerEntity, CustomerEntityDto>(); 

     //AddressEntity Mapping 
     CreateMap<AddressEntity, AddressEntityDto>(); 

     //ServiceEntity Mapping 
     CreateMap<ServiceEntity, ServiceEntityDto>() 
      .ForMember(dto => dto.ServiceTypeCode, opt => opt.MapFrom(source => source.TypeCode)) 
      .ForMember(dto => dto.ServiceDescriptionCode, opt => opt.MapFrom(source => source.DescriptionCode)) 
      .ForMember(dest => dest.SourceSystemName, opt => opt.ResolveUsing<SourceSystemNameResolver>().FromMember(entity => entity.SourceSystemName)); 


     //VehicleEntity Mapping 
     CreateMap<VehicleEntity, VehicleEntityDto>() 
      .ForMember(dest => dest.SourceSystemName, opt => opt.ResolveUsing<SourceSystemNameResolver>().FromMember(entity => entity.SourceSystemName)) 
      .ForMember(dto => dto.PortalId, option => option.Ignore()); //TODO: Should PortalID be mapped to anything? It is not in the entity. 

     //ContentEntity Mapping 
     CreateMap<ContentEntity, ContentEntityDto>() 
      .ForMember(dest => dest.SourceSystemName, opt => opt.ResolveUsing<SourceSystemNameResolver>().FromMember(entity => entity.SourceSystemName)); 

     //OrderForwardingEntity Mapping 
     CreateMap<OrderForwardingEntity, OrderForwardingEntityDto>(); 

     //ContainerEntity Mapping 
     CreateMap<ContainerEntity, ContainerEntityDto>() 
      .ForMember(dest => dest.SourceSystemName, opt => opt.ResolveUsing<SourceSystemNameResolver>().FromMember(entity => entity.SourceSystemName)); 

     //ShipmentForwardingEntity Mapping 
     CreateMap<ShipmentForwardingEntity, ShipmentForwardingEntityDto>(); 


     //ShipmentRouting Mapping 
     CreateMap<ShipmentRoutingEntity, ShipmentRoutingEntityDto>(); 

     //ShipmentEntity Mapping 
     CreateMap<ShipmentEntity, ShipmentEntityDto>() 
      .ForMember(dest => dest.SourceSystemName, opt => opt.ResolveUsing<SourceSystemNameResolver>().FromMember(entity => entity.SourceSystemName)) 
      .ForMember(dto => dto.Services, option => option.MapFrom(source => source.ServiceEntities)); 

     //Forwarder mapping 
     CreateMap<ContactEntity, ForwarderEntityDto>(); 
     //TODO: This property doesn't have any properties in the data contract 

     //OrderEntity Mapping 
     CreateMap<OrderEntity, OrderEntityDto>() 
      .ForMember(dest => dest.SourceSystemName, 
         opt => opt.ResolveUsing<SourceSystemNameResolver>().FromMember(entity => entity.SourceSystemName)); 
      //.ForMember(dto => dto.Forwarder, option => option.MapFrom(entity=>entity.Forwarder) 

     //MoveEntityMapping 
     CreateMap<MoveEntity, MoveEntityDto>() 
      .ForMember(dto => dto.SourceSystemName, opt => opt.ResolveUsing<SourceSystemNameResolver>().FromMember(entity => entity.SourceSystemName)); 

    } 
1

Es necesario añadir configuraciones de asignación de tipos de propiedades en las que el tipo de propiedad de destino es diferente al tipo de propiedad de destino.

Mapper.CreateMap<ContactEntity, TransfereeEntity>(); 
4

Sé que ya lo consiguió, pero voy a tirar esto en caso de que otras personas aterricen aquí.

En AutoMapper, cuando tiene objetos anidados que deben mapearse, incluso si son exactamente iguales (es decir, una clase de contrato y una clase de modelo que coinciden), debe definir mapas para las clases secundarias, luego al definir el mapa para el elemento primario, dentro de la opción '.ForMember' puede usar esos mapas secundarios para asignar el elemento primario. Sé que esto puede sonar confuso pero un ejemplo lo dejará en claro.

Digamos que tienes una la siguiente:

namespace Contracts.Entities 
{ 
    public class Person 
    { 
     public string FirstName {get; set;} 

     public string LastName {get; set;} 

     public Address Address {get; set;}   
    } 

    public class Address 
    { 
     public string Street {get; set;} 

     public string City {get; set;} 

     public string State {get; set;}   
    } 
} 

namespace Model.Entities 
{ 
    public class Person 
    { 
     public string FirstName {get; set;} 

     public string LastName {get; set;} 

     public Address Address {get; set;}   
    } 

    public class Address 
    { 
     public string Street {get; set;} 

     public string City {get; set;} 

     public string State {get; set;}   
    } 
} 

Luego vas y definir los siguientes mapas:

Mapper.CreateMap<Contracts.Entities.Person, Model.Entities.Person>(); 
    Mapper.CreateMap<Contracts.Entities.Address, Model.Entities.Address>(); 

Usted puede pensar que AutoMapper sabría usar el mapa de direcciones cuando la asignación de un contrato persona a una persona modelo, pero no es así. En su lugar, esto es lo que tiene que hacer:

 Mapper.CreateMap<Contracts.Entities.Person, Model.Entities.Person>() 
        .ForMember(dest => dest.Address, opt => opt.MapFrom(src => Mapper.Map<Contracts.Entities.Address, Model.Entities.Address>(src.Address))); 

Mapper.CreateMap<Contracts.Entities.Address, Model.Entities.Address>(); 

Así que en su caso se podría definir un mapa Mapper.CreateMap<ContactEntity,TransfereeEntity>() luego llamar a ese mapa de la misma manera que la dirección anterior al definir el mapa de PrimaryOriginTransferee. ES DECIR.

Mapper.CreateMap<MoveEntity, MoveEntityDto>() 
.ForMember(dest => dest.PrimaryOriginTransferee , opt => opt.MapFrom(src => Mapper.Map<ContactEntity,TransfereeEntity>(src.PrimaryOriginTransferee))); 

Espero que esto ayude a alguien!

Cuestiones relacionadas