Automapper map one property to multiple

JAVH picture JAVH · Nov 13, 2014 · Viewed 8.4k times · Source

I am facing a challenge with AutoMapper between my source object and destination object. I will try to explain the sittuation. On my src object I have an string that according to its lenght it should be mapped to multiple properties of my destination object.

class source
{
   public int Id {get; set;}
   /* some other properties */
   public string Value {get; set;}
}

class destination
{
   public int Id {get; set;}
   /* some other properties with the same name as the source */
   public string Value1 {get; set;}
   public string Value2 {get; set;}
   public string Value3 {get; set;}
}

The max length expected is 30 chars (It can be less than that which will be mapped to only two properties or one). So every 10 will be mapped to each destination property. I was trying to use the ResolveUsing method from AutoMapper but there is no way to let the function to know which segment I should bring back. So I was thinking to ignore the mapping of this properties and do this manually after Automapper has dones its job with other properties

Answer

Andrew Whitaker picture Andrew Whitaker · Nov 13, 2014

On way you could do this is to use .ConstructUsing to tell AutoMapper how to create the object You could create a function that maps Value1, Value2, Value3 manually, then letting AutoMapper map the remaining properties. For example:

static destination ConstructDestination(source src)
{
    List<string> chunked = src.Value
        .Select((ch, index) => new { Character = ch, Index = index })
        .GroupBy(
            grp => grp.Index / 10,
            (key, grp) => new string(grp.Select(itm => itm.Character).ToArray()))
        .ToList();

    var dest = new destination
    {
        Value1 = chunked.Count > 0 ? chunked[0] : null,
        Value2 = chunked.Count > 1 ? chunked[1] : null,
        Value3 = chunked.Count > 2 ? chunked[2] : null
    };

    return dest;
}

Mapper.CreateMap<source, destination>()
    .ConstructUsing(ConstructDestination)
    .ForMember(dest => dest.Value1, opt => opt.Ignore())
    .ForMember(dest => dest.Value2, opt => opt.Ignore())
    .ForMember(dest => dest.Value3, opt => opt.Ignore());
    /* Id is mapped automatically. */

Of course if in your actual scenario you have more than three Value fields, this could become nasty--in that case you could use reflection to set the properties.