1

I have defined a mapping from one type to DTO. Another type references the first type as an property, but the output should be an flattened DTO that should use the already defined mapping for the first type.

class Program {
    static void Main(string[] args) {
        var mapperConfiguration = new MapperConfiguration(cfg => {
            cfg.CreateMap<FirstDataType,
            FirstTypeDto>().ForMember(d => d.TypeResult, opt => opt.MapFrom(s => s.ToString()));

            /* HOW TO CONFIGURE MAPPING OF THE 'FirstData' PROPERTY TO USE THE ABOVE DEFINED MAPPING
                cfg.CreateMap<SecondDataType, SecondTypeDto>()
                */
        });

        var firstData = new FirstDataType {
            TypeName = "TestType",
            TypeValue = "TestValue"
        };

        var secondData = new SecondDataType {
            Id = 1,
            Name = "Second type",
            FirstData = firstData
        };

        var mapper = mapperConfiguration.CreateMapper();

        var firstDto = mapper.Map<FirstTypeDto>(firstData);
        var secondDto = mapper.Map<SecondTypeDto>(secondData);

        Console.ReadKey(true);
    }
}

public class FirstDataType {
    public string TypeName {
        get;
        set;
    }

    public string TypeValue {
        get;
        set;
    }

    public override string ToString() {
        return $ "{TypeName}: {TypeValue}";
    }
}

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

    public string Name {
        get;
        set;
    }

    public FirstDataType FirstData {
        get;
        set;
    }
}

public class FirstTypeDto {
    public string TypeName {
        get;
        set;
    }

    public string TypeValue {
        get;
        set;
    }

    public string TypeResult {
        get;
        set;
    }
}

public class SecondTypeDto: FirstTypeDto {
    public int Id {
        get;
        set;
    }

    public string Name {
        get;
        set;
    }
}

How should I configure mapping for the second type to use the defined mapping for the property 'FirstData'?

Thanks!

Glumac
  • 31
  • 7
  • 1
    Should `SecondDataType` inherit from `FirstDataType` as with their corresponding DTOs? – Johnathan Barclay Jan 10 '20 at 14:09
  • Please Add the expected result. – ljcordero Jan 10 '20 at 14:11
  • Yes, it should extend the `FirstDataType`, map it as flattened, but use the already defined mapping (to keep the code DRY). – Glumac Jan 10 '20 at 14:12
  • I Think: `cfg.CreateMap() .ForMember(d => d.TypeName, opt => opt.MapFrom(s => s.FirstData.TypeName )) .ForMember(d => d.TypeValue, opt => opt.MapFrom(s => s.FirstData.TypeValue )) .ForMember(d => d.TypeResult, opt => opt.MapFrom(s => s.FirstData.ToString() ));` – ljcordero Jan 10 '20 at 14:14
  • @ljcordero: this what is expected `secondDto = { Id = 5, Name = "Second type", TypeName = "TestType", TypeValue = "TestValue", TypeResult = "TestType: TestValue" }` – Glumac Jan 10 '20 at 14:15
  • http://docs.automapper.org/en/latest/Flattening.html – Lucian Bargaoanu Jan 10 '20 at 14:17
  • @ljcordero: Thanks, but I need to use the already defined mapping. For the sake of brevity I've made a small sample, the real types are much larger and having two places to maintain the code isn't a good option. – Glumac Jan 10 '20 at 14:19
  • @LucianBargaoanu: Thanks, I saw that, but as far as I see that is not supported in version 6.2.2, or maybe I haven't added some extension methods? – Glumac Jan 10 '20 at 14:22
  • You need to upgrade. That's ancient history. – Lucian Bargaoanu Jan 10 '20 at 14:43
  • @LucianBargaoanu: I've made a side project to test out IncludeMembers, but it seems it doesn't use the mapping for the nested object, the `TypeResult` proprety is `null`. – Glumac Jan 10 '20 at 15:26
  • You're missing smth, check the tests in the repo. – Lucian Bargaoanu Jan 10 '20 at 15:39
  • @LucianBargaoanu: after some research, AutoMapper does not reuse the mapping for the base type. It is capable to "reuse" mapping (rather include), but only for the derived type, in which case you would need two mappings. – Glumac Jan 12 '20 at 16:40
  • I'm not sure what your point is. In order to reuse a mapping, you obviously need two :) – Lucian Bargaoanu Jan 12 '20 at 17:30
  • @LucianBargaoanu: I meant two mappings for the base type `FirstDataType` - one for `FirstTypeDto` and another for derived `SecondTypeDto`. I was hoping that there is a way to tell AutoMapper "hey, the destination DTO is a derived type with a defined mapping, so when flattening use that one". – Glumac Jan 12 '20 at 18:09
  • A map for a base type will be used for a derived type, but of course only for the base members. When you have extra derived members to map, you need the derived map. See also http://docs.automapper.org/en/latest/Mapping-inheritance.html. – Lucian Bargaoanu Jan 12 '20 at 18:21
  • @LucianBargaoanu: first off, thanks a lot for your help :) The problem is I want to do a flattening into the derived type. Of course, I'll specify the extending members of the derived type, but I don't know how to tell AutoMapper to flatten a complex type into a derived type, but to reuse the mapping for the base type. – Glumac Jan 12 '20 at 18:54
  • 1
    It seems to me that you just need to use `IncludeMembers` _and_ `Include`. – Lucian Bargaoanu Jan 12 '20 at 19:36
  • @LucianBargaoanu: The base type mapping should be unaware of the derived type, so I could use `IncludeBase` on the derived type mapping, except, the only derived type is the DTO, not the data type. To flatten with the `IncludeMember`, I'd need to create a mapping from the associated typed to the derived DTO, basically can not reuse the mapping. So I'm back at square one :( – Glumac Jan 12 '20 at 20:52

1 Answers1

1

First, credit goes to Lucian Bargaoanu for leading me in the right direction. Basically, you need to create a mapping from the source to the destination derived type, but just include the existing mapping.

cfg.CreateMap<FirstDataType, SecondTypeDto>()
                .IncludeBase<FirstDataType, FirstTypeDto>()
                .ReverseMap();

cfg.CreateMap<SecondDataType, SecondTypeDto>()
                .IncludeMembers(s => s.FirstData)                    
                .ReverseMap();
Glumac
  • 31
  • 7