I'm using automapper via DI and want to have generic rules for all the mappings found in my solution. Belows example is of a single class, however I've got hundreds of classes to maintain and therefore want to add it to the mapper, not the mapping profile. So far, I can handle Null values as follows :
cnfg.ForAllMembers(opts => opts.Condition((src, dest, srcMember) => srcMember != null)));
Which in my example below, allows for the null update to persist past all the subsiquent updates. What I want is a generic rule ( or statement) for the default value of Guids, DateTimeOffset and Int. In my example below, update 1 and 2 are lost once update 3 is mapped.
using System;
using Autofac;
using AutoMapper;
namespace AutoMapperProblem
{
public class Program
{
static void Main(string[] args)
{
var builder = new ContainerBuilder();
builder.RegisterInstance(new MapperConfiguration(cfg =>
{
cfg.AddMaps(typeof(Program).Assembly);
cfg.ForAllMaps((obj, cnfg) =>
cnfg.ForAllMembers(opts => opts.Condition((src, dest, srcMember) => srcMember != null)));
}).CreateMapper()).As<IMapper>().SingleInstance();
var container = builder.Build();
var mapper = container.Resolve<IMapper>();
var MainObject = new MainObject();
//this update persists pass all updates
var updateNull = new UpdateObject { NullGuid = Guid.NewGuid() };
mapper.Map(updateNull, MainObject);
var update1 = new UpdateObject { DateTimeOffset = DateTimeOffset.Now };
mapper.Map(update1, MainObject);
var update2 = new UpdateObject { Guid = Guid.NewGuid() };
mapper.Map(update2, MainObject);
var update3 = new UpdateObject { Int = 10 };
mapper.Map(update3, MainObject);
}
}
public class MappingProfile : Profile
{
public MappingProfile()
{
CreateMap<MainObject, UpdateObject>()
.ReverseMap();
}
}
public class MainObject
{
public Guid? NullGuid { get; set; }
public Guid Guid { get; set; }
public int Int { get; set; }
public DateTimeOffset DateTimeOffset { get; set; }
}
public class UpdateObject
{
public Guid? NullGuid { get; set; }
public Guid Guid { get; set; }
public int Int { get; set; }
public DateTimeOffset DateTimeOffset { get; set; }
}
}
I want it to work based on the type, eg ints, DateTimeOffsets and Guid's .
Heres a working example on DotNetFiddle : https://dotnetfiddle.net/Zh0ta6
Thanks for any help with this
The problem is that you cannot check value types against
nullin youropts.Condition()check, as they always have a value. Also, you can't use thedefaultkeyword directly in this specific context because the variable type isobject. That will turndefaulttonullagain, and fail.Depending on what you want to do, you can check if the destination already have a non-default value and do NOT replace it with any source value, which might be the default value of the type (
0forint,0000...-000forGuid, etc.). The check could look like this:The first part is calculating the default value for the given destination value, based on the type of the destination value. The latter part is checking if the destination already have a non-default value or not. Consecutive calls of
Map()with the same target object will fill the "missing" property values until all the property values are set (in this example). If necessary, check thesrcMembervalue and it's default type as well to fine-tune when the value should be copied or not.