0

I'm currently experiencing an issue when trying to map the entire destination object from a child property on the source object. Something similar as described here: Automapper - How to map from source child object to destination

I've made use of the .ConstructUsing method as described in the link above however I'm seeing some weird behaviour where the outputted, mapped object is getting values from the parent instead of the child.

I made a demo of the problem here: https://dotnetfiddle.net/OdaGUr

Is this a problem with my code, should I be using a different method to achieve what I'm trying to do or is this a fault with AutoMapper?

EDIT:

public static void Main()
{
    var config = new MapperConfiguration(cfg => {
        cfg.CreateMap<Child1, Child2>();
        cfg.CreateMap<Parent, Child2>().ConstructUsing((src, ctx) => ctx.Mapper.Map<Child2>(src.Child1));   
     });

    var mapper = config.CreateMapper();

    var parent = new Parent{
        Id = 1,
        Child1 = new Child1 {
            Id = 2
        }
    };

    var child2 = mapper.Map<Parent, Child2>(parent);
    Console.WriteLine(child2.Id); // Returns 1. Expect this to be 2 from Parent.Child1
}

public class Parent
{
    public int Id {get;set;}
    public Child1 Child1 {get;set;}
}

public class Child1
{
    public int Id {get;set;}
}

public class Child2
{
    public int Id {get;set;}
}
d00M_L0rDz
  • 21
  • 3
  • https://docs.automapper.org/en/latest/Flattening.html – Lucian Bargaoanu Jun 12 '20 at 13:11
  • @LucianBargaoanu Sorry, which part of this should I be looking at? To me, in the example I've given, AutoMapper should pull all the property values from Child1 and none from the Parent. I can see that I can ignore the Id using `ForMember(src => src.Id, opt => opt.Ignore())` before calling `.ConstructUsing` and then it will get it from Child1, but I don't quite grasp the flow of why it is opting for the Parent over Child1 without this? – d00M_L0rDz Jun 12 '20 at 13:34
  • That's what it's supposed to do :) You mean `ConvertUsing`, not `ConstructUsing`. Check [the execution plan](https://docs.automapper.org/en/latest/Understanding-your-mapping.html). – Lucian Bargaoanu Jun 12 '20 at 13:38
  • @LucianBargaoanu Sorry, I think I'm confused. In my demo of the problem I'm using `ConstrustUsing`: `cfg.CreateMap().ConstructUsing((src, ctx) => ctx.Mapper.Map(src.Child1));` Is that not right? – d00M_L0rDz Jun 12 '20 at 13:46

1 Answers1

2

ConstructUsing() is used to create the destination object, where the value should be stored in. In your case you are returning a Child2 object with the Id value set to 2 (as returned by the ctx.Mapper.Map<Child1, Child2>(src.Child1) line).

However, after the object has been created, the default mapping will still be applied. This means that the Parent.Id value will be saved in the Child2.Id property, because the names of the property match ("Id"). So, the initial value of 2 will be replaced with the value 1 from the Parent object.

Depending on what you want to do, you might want to use ForMember() to configure special handling on how the property values should be mapped. An example would be:

.ForMember(dest => dest.Id, src => src.MapFrom(it => it.Child1.Id))
Progman
  • 16,827
  • 6
  • 33
  • 48
  • Cheers for the explanation, I will look at doing this. Also edited my post to include the code from my demo. – d00M_L0rDz Jun 12 '20 at 17:08