I am using Automapper for mapping DB entities from entity framework to business objects through ProjectTo<>()
. Now I'd like to map/project nullable decimal to class type and don't want to specify manual mapping of these two types for every property in each object so I decided to use a custom type converter and the Automapper will do the work. When a decimal?
property has value it works fine but when it is null (and the DB table column allows NULLs) it throws an exception saying "Null TypeMapping in Sql Tree" and the converter's Convert()
method is not called at all. The code is as follows:
basic class type and derived (one of many)
public abstract class BaseUnit
{
public decimal? DefaultValue { get; protected set; }
public abstract ViewableUnit GetRequestedUnit(Unit unit);
}
public class Density : BaseUnit
{
public Density()
{
this.DefaultValue = decimal.Zero;
}
public Density(decimal? densityInGperL)
{
this.DefaultValue = densityInGperL;
}
public decimal? GramsPerLiter
{
get => this.DefaultValue;
set => this.DefaultValue = value;
}
public decimal? GramsPerDeciliter
{
get => this.DefaultValue * 10;
set => this.DefaultValue = value * 0.1m;
}
public override ViewableUnit GetRequestedUnit(Unit unit)
{
...
}
}
converter and registration
public class DecimalUnitTypeConverter : ITypeConverter<decimal?, Density>
{
public Density Convert(decimal? source, Density destination, ResolutionContext context)
{
return source.HasValue ? new Density(source.Value) : null;
}
}
Mapper.CreateMap(typeof(decimal?), typeof(Density)).ConvertUsing(typeof(DecimalUnitTypeConverter));
DB entity and DTO
public class LabResult
{
decimal? NumberResult { get; set; }
...
}
public class LabResultDto
{
Density NumberResult { get; set; }
public void CreateMappings(Profile configuration)
{
configuration.CreateMap<LabResult, LabResultDto>()
.ForMember(
dst => dst.NumberResult,
opt =>
{
opt.PreCondition(src => src.NumberResult.HasValue); // does not have to be here, the outcome is the same
opt.MapFrom(src => src.NumberResult);
});
}
}
and final usage
dbContext.LabResults.AsNoTracking()
.Where(lab => lab.Id == request.Id)
.ProjectTo<LabResultDto>(this.configurationProvider)
.ToList();
I know that Map and ProjectTo work differently but I thought that this type of mapping / projection is trivial even if I tell the Automapper how to do it via type converter. Am I missing something? Thanks for any kind of help.