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
Automapper is considerably faster when mapping a List<T> of objects on . NET Core (It's still slower on full . NET Framework).
AutoMapper supports polymorphic arrays and collections, such that derived source/destination types are used if found.
Mapster is an emerging alternative to AutoMapper which was first published in 2015 and has over 7.4 million NuGet package downloads.
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.
You can create a mapping function using the ForMember specification
I.e.
private void CreateMap(){
Mapper.CreateMap<source,destination>()
.ForMember(v=> v.Value1,
opts => opts.MapFrom( src=> src.Value.Substring(0,10)))
.ForMember(v=> v.Value2,
opts => opts.MapFrom( src=> src.Value.Substring(10,10)))
.ForMember(v=> v.Value3,
opts => opts.MapFrom( src=> src.Value.Substring(20,10)));
}
You can just evaluate on every mapping that the original string contains the appropiate lenght and otherwise return string.Empty or stuff it to suit your needs.
Usage(using LinqPad):
void Main(){
CreateMap();
var source = new source();
source.Id=1;
source.Value="123454678901234546789012345467";
var res = Mapper.Map<destination>(source);
res.Dump();
}
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With