5

Consider these classes as source:

public class SourceParent
{
    public int X { get; set; }
    public SourceChild1 Child1 { get; set; }
    public SourceChild2 Child2 { get; set; }
}

public class SourceChild1
{
    public int A { get; set; }
    public int B { get; set; }
    public int C { get; set; }
    public int D { get; set; }
}

public class SourceChild2
{
    public int I { get; set; }
    public int J { get; set; }
    public int K { get; set; }
    public int L { get; set; }
}

I'm trying to map the source to a destination similar to this:

public class Destination
{
    public int X { get; set; }

    public int A { get; set; }
    public int B { get; set; }
    public int C { get; set; }
    public int D { get; set; }

    public int I { get; set; }
    public int J { get; set; }
    public int K { get; set; }
    public int L { get; set; }
}

Well, using this configuration, it is possible to do the mapping:

Mapper.CreateMap<SourceParent, Destination>()
    .ForMember(d => d.A, opt => opt.MapFrom(s => s.Child1.A))
    .ForMember(d => d.B, opt => opt.MapFrom(s => s.Child1.B))
    .ForMember(d => d.C, opt => opt.MapFrom(s => s.Child1.C))
    .ForMember(d => d.D, opt => opt.MapFrom(s => s.Child1.D))
    .ForMember(d => d.I, opt => opt.MapFrom(s => s.Child2.I))
    .ForMember(d => d.J, opt => opt.MapFrom(s => s.Child2.J))
    .ForMember(d => d.K, opt => opt.MapFrom(s => s.Child2.K))
    .ForMember(d => d.L, opt => opt.MapFrom(s => s.Child2.L));

Except that, when the child class has many properties, all of which having the same name with the parent, this is not a clean way.

Ideally, I'd like to tell AutoMapper to take Source.Child1 and Source.Child2 as a source too, and map every matching property names to the target (instead of specifying every single property); something like this:

Mapper.CreateMap<SourceParent, Destination>()
    .AlsoUseSource(s => s.Child1)
    .AlsoUseSource(s => s.Child2);
Iravanchi
  • 5,139
  • 9
  • 40
  • 56

1 Answers1

3

You can use .ConstructUsing to accomplish this. It's not the cleanest looking thing in the world, but it'll work:

/* Map each child to the destination */
Mapper.CreateMap<SourceChild1, Destination>();
Mapper.CreateMap<SourceChild2, Destination>();

Mapper.CreateMap<SourceParent, Destination>()
    .ConstructUsing(src =>
    {
        /* Map A-D from Child1 */
        var dest = Mapper.Map<Destination>(src.Child1);

        /* Map I-L from Child2 */
        Mapper.Map(src.Child2, dest);

        return dest;
    });
/* X will be mapped automatically. */

This should successfully map all of the properties.

Unfortunately, a call to .AssertConfigurationIsValid will fail, since properties I - L will not be mapped on the destination type for the mapping from SourceParentDestination.

You could, of course, write a call to .Ignore for each one, but that would kind of defeat the purpose of getting rid of the nested mapping calls.

Your other option would be to leverage this awesome answer to ignore unmapped properties on each of the mappings.

Community
  • 1
  • 1
Andrew Whitaker
  • 124,656
  • 32
  • 289
  • 307
  • Thanks, this is useful. Actually I ended up doing something similar (doing the same thing using `AfterMap`). But I'll leave the question unanswered for another day or two, to see if anyone else comes with a "cleaner" answer. – Iravanchi Nov 12 '14 at 06:47