简体   繁体   English

自动映射自定义映射异常

[英]Automapper Custom Mapping Exception

Update 1-13-10 I've been able to find some success using the code below for mapping. 更新1-13-10我已经能够使用下面的代码找到一些成功的映射。 I am essentially ignoring any of the properties that do not have a mapping and mapping them afterwards. 我基本上忽略了没有映射的任何属性,然后映射它们。 I would appreciate feedback as to whether or not I am going about this in the best way possible. 我希望得到关于我是否以最佳方式进行此项讨论的反馈意见。 In addition, I am not sure how to go about unit testing this mapping. 另外,我不知道如何进行单元测试这种映射。 It was my impression that using the AutoMapper should help alleviate tediousness of checking each property. 我的印象是使用AutoMapper应该有助于减轻检查每个属性的繁琐。

Here is my new code: 这是我的新代码:

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

Original Post: 原帖:

I'm attempting to use AutoMapper for the first time in order to map from a Bussiness Object to a DTO. 我第一次尝试使用AutoMapper,以便从Bussiness对象映射到DTO。 I am running into issues that I do not know how to troubleshoot, including the following exception: 我遇到了一些我不知道如何排除故障的问题,包括以下异常:

AutoMapper.AutoMapperMappingException: Trying to map Graebel.SP.BO.MoveEntity to Graebel.SOA.Contracts.DataContracts.SP.MoveEntity. AutoMapper.AutoMapperMappingException:尝试将Graebel.SP.BO.MoveEntity映射到Graebel.SOA.Contracts.DataContracts.SP.MoveEntity。 Exception of type 'AutoMapper.AutoMapperMappingException' was thrown 抛出了“AutoMapper.AutoMapperMappingException”类型的异常

Here is the AutoMapper Code that I am running: 这是我正在运行的AutoMapper代码:

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

Here is the DTO (MoveEntityDto) that I am attempting to map: 这是我试图映射的DTO(MoveEntityDto):

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

Here is the Business Object (MoveEntity) that I am trying to map from 这是我想要映射的业务对象(MoveEntity)

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

The properties within each class almost match up perfectly by name, but their types are different. 每个类中的属性几乎完全匹配名称,但它们的类型是不同的。 Therefore I have attempted to perform a custom mapping using the "MapFrom" expression. 因此,我尝试使用“MapFrom”表达式执行自定义映射。 However, AutoMapper doesn't seem to be able to allow me to point from one object type to another without complain. 但是,AutoMapper似乎无法让我在没有抱怨的情况下从一种对象类型指向另一种对象类型。

I've also tried mapping property-to-property, with no luck. 我也尝试过映射属性到属性,没有运气。 It looked something like this: 它看起来像这样:

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

However, when attempting this, I receive the following exeception: 但是,在尝试此操作时,我收到以下异常:

must resolve to top-level member. 必须解决顶级成员。 Parameter name: lambdaExpression. 参数名称:lambdaExpression。

I have been finding the documentation available for AutoMapper difficult to follow. 我一直在寻找AutoMapper可用的文档很难理解。 Can someone please point me in the right direction as to how to use this utility correctly? 有人可以指出我正确的方向如何正确使用此实用程序?

Thanks in advance for any help! 在此先感谢您的帮助!

Adam 亚当

I finally ended up getting this to work on my own. 我终于得到了自己的工作。 The code I ended up using is posted below. 我最终使用的代码发布在下面。 Creating the map of objects in the correct order proved to be important. 以正确的顺序创建对象的地图被证明是重要的。 I learned a lot fighting through this thing. 我通过这件事学到了很多东西。

I've organized my mappings into a profile, which I won't get into here, suffice to say that if you can use my example outside of a class inheriting from the AutoMapper Profile class, you'll want to use Mapper.CreateMap instead of just Create Map. 我已经将我的映射组织到一个配置文件中,我不会进入这里,只要说如果你可以在继承自AutoMapper Profile类的类之外使用我的例子,你将需要使用Mapper.CreateMap代替只是创建地图。

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

    }

I know you already got this working but Im going to throw this out there in case other people land here. 我知道你已经有了这个工作但我会把它扔到那里以防其他人降落在这里。

In AutoMapper, when you have nested objects that need to be mapped, even if they are exactly the same (ie. a contract class and a model class that match), you have to define maps for the child classes, then when defining the map for the parent, inside the '.ForMember' option you can use those child maps to map the parent. 在AutoMapper中,当您拥有需要映射的嵌套对象时,即使它们完全相同(即合同类和匹配的模型类),您必须为子类定义映射,然后在定义映射时对于父级,在“.ForMember”选项中,您可以使用这些子映射来映射父级。 I know this may sound confusing but an example will make it clear. 我知道这可能听起来令人困惑,但一个例子会说清楚。

Say you have a the following: 假设您有以下内容:

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

Then you go and define the following maps: 然后你去定义以下地图:

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

You may think that AutoMapper would know to use the Address map when mapping a Contract person to a model person but it does not. 您可能认为AutoMapper在将Contract人员映射到模型人员时会知道使用地址映射,但事实并非如此。 Instead, here is what you have to do: 相反,这是你必须做的:

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

So in your case you could define a Mapper.CreateMap<ContactEntity,TransfereeEntity>() map then call that map in the same way as address above when defining the map for PrimaryOriginTransferee. 因此,在您的情况下,您可以定义Mapper.CreateMap<ContactEntity,TransfereeEntity>()地图,然后在为PrimaryOriginTransferee定义地图时以与上面地址相同的方式调用该地图。 IE IE

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

Hope this helps someone! 希望这有助于某人!

您需要为目标属性类型与目标属性类型不同的属性类型添加映射配置。

    Mapper.CreateMap<ContactEntity, TransfereeEntity>();

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM