Pankaj Kaushik
Pankaj Kaushik

Reputation: 137

How to map two different datatype fields using Automapper?

I am trying to map fields of an object with child collection of source using Automapper through ProjectTo IQueryable as following:

var map2 = cfg.CreateMap<SourceModel, DestinationModel>(); 

map2.ForMember(fieldName, opt => opt.MapFrom(source => source.CustomFieldValues.FirstOrDefault(f => f.Name == fieldName).Value));

Models are as following:

public class SourceModel
{
  public IEnumerable<CustomFieldValue> CustomFieldValues { get; set; }
}

public class CustomFieldValue
{

    public string Name { get; set; }
    public string Value { get; set; }
}

public class DestinationModel
{
    public string _CUSTOM_Test { get; set; }
    public int _CUSTOM_Mynumber { get; set; }
    public DateTime _CUSTOM_mydate { get; set; }
    public bool _CUSTOM_mybool { get; set; }
    public decimal _CUSTOM_numberdec { get; set; }
    public int _CUSTOM_numint { get; set; }
    public int _CUSTOM_numper { get; set; }
    public DateTime _CUSTOM_mydate2 { get; set; }
    public DateTime _CUSTOM_mydate3 { get; set; }
    public DateTime _CUSTOM_mydate4 { get; set; }
    public int _CUSTOM_mynum2 { get; set; }
}

Expected Result: As the collection contains only string values but I need to map with different datatypes based on field name.

Actual Result: But when I try to apply conversion then queryable throws exception because sql query doesn't support this conversion.

Upvotes: 4

Views: 3557

Answers (1)

TimAlonso
TimAlonso

Reputation: 498

You can use AutoMapper's Custom Type Converters.

AutoMapper does not know about any mapping from string to int for example so to create maps for these types, we must supply a custom type converter. This can be achieved by using ConvertUsing() method.

Mapper.Initialize(configuration =>
{
    configuration.CreateMap<string, int>().ConvertUsing(s => Convert.ToInt32(s));
    configuration.CreateMap<string, DateTime>().ConvertUsing(s => new DateTimeTypeConverter().Convert(s));
    configuration.CreateMap<string, bool>().ConvertUsing(s => Convert.ToBoolean(s));
    configuration.CreateMap<string, decimal>().ConvertUsing(s => Convert.ToDecimal(s));
    configuration.CreateMap<SourceModel, DestinationModel>()
        .ForMember("_CUSTOM_Mynumber", opt => opt.MapFrom(src => src.CustomFieldValues.FirstOrDefault(x => x.Name == "_CUSTOM_Mynumber").Value));
});

The example above shows how we can convert int, bool, and decimal. For DateTime, we'll use ITypeConverter.

public interface ITypeConverter<in TSource, TDestination>
{
    TDestination Convert(TSource source);
}

Then define a custom convertion:

public class DateTimeTypeConverter : ITypeConverter<string, DateTime>
{
    public DateTime Convert(string source)
    {
        return Convert.ToDateTime(source);
    }
}

Upvotes: 3

Related Questions