-1

My class XmlOrder contains the two properties

public class XmlOrder
{
    public OrderType OrderType { get; set; }
    public object Item { get; set; }
}

If OrderType equals OrderType.Service, Item will be of type XmlTransportElement. If it is OrderType.Transport, it will be of type XmlTransport. XmlTransport has the following two properties:

public class XmlTransport
{
    public XmlTransportElement Delivery { get; set; }
    public XmlTransportElement Pickup { get; set; }
}

XmlOrder needs to be mapped to Order which looks like this:

 public class Order : IOrder
 {
     public ITransportElement[] TransportElements { get; set; }
 }

This array will either have one or two entries based on the logic above.

In my sample project, I've written this using the latest AutoMapper version, and it works perfectly:

public class OrderProfile : Profile
{
    public OrderProfile()
    {            
        // Mapping for XmlOrder to IOrder
        CreateMap<XmlOrder, IOrder>()
            .ConstructUsing(src => new Order())
            .ForMember(dest => dest.TransportElements, opt => opt.MapFrom((src, dest, _, context) =>
                src.Item is XmlTransport transport
                    ? new[]
                    {
                        transport.Delivery != null ? context.Mapper.Map<TransportElement>(transport.Delivery) : null,
                        transport.Pickup != null ? context.Mapper.Map<TransportElement>(transport.Pickup) : null
                    }
                    : new[] { context.Mapper.Map<TransportElement>((XmlTransportElement)src.Item) }
            ));

        // Mapping for XmlTransportElement to TransportElement
        CreateMap<XmlTransportElement, TransportElement>()
             // additional logic
    }
}

The problem is, I need to implement this in a legacy application using AutoMapper 6.1.1. The above code doesn't work because .MapFrom cannot be used like this in older versions. I've been going in circles for two days and tried various approaches using .ConvertUsing and .ResolveUsing in combination with a custom converter but always get NullReferenceExceptions or other errors.

The latest approach I've tried was this one, which throws an AutoMapperMappingException:

 CreateMap<XmlOrder, IOrder>()
        .ForMember(dest => dest.TransportElements, opt => opt.ResolveUsing(src =>
        {
            var transport = src.Item as Transport;
            if (transport != null)
            {
                return new[]
                {
                    transport.Delivery != null ? Mapper.Map<TransportElement>(transport.Delivery) : null,
                    transport.Pickup != null ? Mapper.Map<TransportElement>(transport.Pickup) : null
                };
            }
            return new[] { Mapper.Map<TransportElement>((XmlTransportElement)src.Item) };
        }))
        .ConstructUsing(src => new Order());

Any help is appreciated. AI hasn't been helpful at all and keeps suggesting things that don't work with this particular AutoMapper version.

4
  • There's too much code missing. What is TransportModel ? What are the actual classes and how was AutoMapper configured? The 6.1.1 code mixes up profiles and the static mapper. That static mapper needs to be configured for TransportElement and whatever transport.Delivery is. Commented Sep 24, 2024 at 14:19
  • From AutoMapper's Design Philosophy written by its creator to warn against such code: AutoMapper works because it enforces a convention. It assumes that your destination types are a subset of the source type. It assumes that everything on your destination type is meant to be mapped. It assumes that the destination member names follow the exact name of the source type. It assumes that you want to flatten complex models into simple ones Commented Sep 24, 2024 at 14:21
  • As for "AI", it doesn't understand anything about programming, it's just a statistical text generator. And the text it was trained on isn't using a 7 year old AutoMapper version. And given the fact that AutoMapper isn't meant for such complex mapping jobs, there aren't many (much less good) examples it could be trained on Commented Sep 24, 2024 at 14:24
  • @PanagiotisKanavos There were a few naming mistakes which I've corrected. We use a lot of similar mapping profiles in our application so this is what I have to work with. Deliveryis a property of type TransportElementas explained above. Mapping 'TransportElement' is straight forward as it only consists of a bunch of strings and other types that already have mapping profiles. My only issue here is how to deal with 'Item' being of type 'object' in the 6.1.1 version. Commented Sep 24, 2024 at 15:21

1 Answer 1

0

Found a solution eventually.

CreateMap<XmlOrder, IOrder>( )
    .ConstructUsing(src => new Order( ))
    .ForMember(dest => dest.TransportElements, opt => opt.ResolveUsing(src => {
        switch (src.Item)
        {
            case XmlTransport xmltransport:
            {
                var elements = new List<TransportElement>( );

                if ( transport.Delivery != null ) {
                    elements.Add(new TransportElement {
                        // additional logic
                    });
                }

                if ( transport.Pickup != null ) {
                    elements.Add(new TransportElement {
                        // additional logic
                    });
                }

                return elements.ToArray( );
            }
            case XmlTransportElement xmlTransportElement:
                return new[]
                {
                    new TransportElement
                    {
                        // additional logic
                };
            default:
                return null;
        }
    }));
Sign up to request clarification or add additional context in comments.

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.