1
votes

I am trying to map one entity object to different view models. I have a base view model and two other view models that derive from the base. The view models are created based on their type property in run time via a factory method. There are no separate entities for the derived view models and source entity has all the properties for the derived view models. The problem is that Automapper is able to create the correct objects through the factory method but the properties in the derived objects are not mapped at all. Only the base view model's properties are mapped.

Sample entities:

public class VehicleEntity
{
    public int Type { get; set; }
    public int LoadCapacity { get; set; }
    public TrailerEntity Trailer { get; set; }
}

public class TrailerEntity
{
    public int Capacity { get; set; }
}

View models:

public class VehicleVM
{
    public int Type { get; set; }
}

public class CarVM: VehicleVM
{
    public TrailerVM Trailer { get; set; }
}

public class TruckVM : VehicleVM
{
    public int LoadCapacity { get; set; }
}

public class TrailerVM
{
    public int Capacity { get; set; }
}

public static class VehicleFactory
{
    public static VehicleVM GetInstance(int type)
    {
        switch (type)
        {
            case 1:
                return new CarVM();
            case 2:
                return new TruckVM();
            default:
                return new VehicleVM();
        }
    }
}

Finally the mapping:

        List<VehicleEntity> vehicleList = new List<VehicleEntity>();
        vehicleList.Add(new VehicleEntity()
        {
            Type = 1,
            LoadCapacity = 0,
            Trailer = new TrailerEntity()
            {
                Capacity = 120
            }
        });

        vehicleList.Add(new VehicleEntity()
        {
            Type = 2,
            LoadCapacity = 8000,
            Trailer = null
        });

        var config = new MapperConfiguration(cfg =>
        {
            cfg.CreateMap<VehicleEntity, VehicleVM>()
                .ConstructUsing((Func<VehicleEntity, VehicleVM>)(rc => VehicleFactory.GetInstance(rc.Type)))
                .Include<VehicleEntity, TruckVM>()
                .Include<VehicleEntity, CarVM>();
            cfg.CreateMap<VehicleEntity, TruckVM>();
            cfg.CreateMap<VehicleEntity, CarVM>();
            cfg.CreateMap<TrailerEntity, TrailerVM>();
        });

        IMapper mapper = config.CreateMapper();
        var vehicleVMs = mapper.Map<List<Data.VehicleEntity>, List<VehicleVM>>(vehicleList);

In above example only the Type properties are mapped in CarVM and TruckVM. Other properties are not... I have also tried using ForMember method in order to map the derived class properties from the source entity but no luck.

cfg.CreateMap<VehicleEntity, TruckVM>().ForMember(dst => dst.LoadCapacity, opt => opt.MapFrom(src => src.LoadCapacity));

Is it possible to achieve this?

1
It doesn't work that way. See here.Lucian Bargaoanu
I am not seeing the inheritance here. Make sure this is close to a minimal reproducible example.Henk Holterman
@HenkHolterman sorry. I have updated my question. The problem is related to automapper is not able to map any property in the derived class.Ahmet Keskin
And does TrailerEntity have a base class?Henk Holterman
Really do go and write that minimal reproducible exampleHenk Holterman

1 Answers

2
votes

You can use following configuration

var config = new MapperConfiguration(
    cfg =>
    {
        cfg.CreateMap<VehicleEntity, VehicleVM>()
            .ConstructUsing(rc => VehicleFactory.GetInstance(rc.Type))
            .BeforeMap((s, d, c) => c.Mapper.Map(s, d));

        cfg.CreateMap<VehicleEntity, TruckVM>();
        cfg.CreateMap<VehicleEntity, CarVM>();
        cfg.CreateMap<TrailerEntity, TrailerVM>();
    });

In this case ConstructUsing creates proper destination object based on Type property and then in BeforeMap maps source VehicleEntity instance to created destination object. You can also do it in AfterMap method.

Or you can create destination object and map source on it immediately in ConstructUsing

var config = new MapperConfiguration(
    cfg =>
    {
        cfg.CreateMap<VehicleEntity, VehicleVM>()
            .ConstructUsing((rc, context) => context.Mapper.Map(rc, VehicleFactory.GetInstance(rc.Type)));

        cfg.CreateMap<VehicleEntity, TruckVM>();
        cfg.CreateMap<VehicleEntity, CarVM>();
        cfg.CreateMap<TrailerEntity, TrailerVM>();
     });