I am using Automapper to map my domain model (nHibernate) to my view models and back. Everything is pretty smooth.
Now I need to map an entity (domain entity) to itself cause I want to define some business rules there.
I need to define different mappings for the same type more than once. I already use profiles for each type of mapping:
public static void Configure()
{
Mapper.Initialize(a =>
{
Mapper.AddProfile(new OrderViewModelMapperProfile());
Mapper.AddProfile(new OrderToOrder1MapperProfile());
Mapper.AddProfile(new OrderToOrder2MapperProfile());
});
}
And this is my profile (simplified):
public class OrderToOrder1MapperProfile : Profile
{
protected override void Configure()
{
this.CreateMap<Domain.Order, Domain.Order>()
.WithProfile("Profile001")
.ForMember(dest => dest.Code, opt => opt.MapFrom(source => System.Guid.Empty))
.ForMember(dest => dest.OrderLines, opt => opt.Ignore())
.AfterMap((source, destination) =>
{
foreach (var line in source.OrderLines)
{
destination.AddOrderLine(Mapper.Map<Domain.OrderLine, Domain.OrderLine>(line));
}
});
this.CreateMap<Domain.OrderLine, Domain.OrderLine>()
.ForMember(dest => dest.Order, opt => opt.Ignore())
.ForMember(dest => dest.Code, opt => opt.MapFrom(source => System.Guid.Empty));
}
}
As you can see I need to do a few things in AfterMap.
My second profile OrderToOrder2MapperProfile looks similar to the one show here so I won't paste the code.
When I map my object:
Domain.Order order = new Domain.Order();
var order2 = Mapper.Map<Domain.Order, Domain.Order>(order);
both profiles are processed.
I decided to follow the path suggested on SO and I've created my "custom" engine:
private IMappingEngine CustomMappingEngine()
{
ConfigurationStore store = new ConfigurationStore(new TypeMapFactory(), MapperRegistry.Mappers);
MappingEngine engine = new MappingEngine(store);
store.AddProfile(new OrderToOrder2MapperProfile());
store.AllowNullDestinationValues = true;
store.AssertConfigurationIsValid();
return (engine);
}
Now everything works fine except for the mapping of the lines; both pipes are processed even if I am using the custom engine to map my object:
Domain.Order order = new Domain.Order();
var newEngine = CustomMappingEngine();
var order2 = newEngine.Map<Domain.Order, Domain.Order>(order);
I guess the problem sits in the fact that I am using the singleton Mapper (engine) here:
destination.AddOrderLine(Mapper.Map<Domain.OrderLine, Domain.OrderLine>(line))
I've tried to find a way to using the current engine inside a profiler but I don't seem to be able to get it in any way.
The only possible solution is to pass the engine in the constructor of my profiler:
public class OrderToOrder2MapperProfile : Profile
{
private readonly IMappingEngine CurrentMappingEngine = null;
public OrderToOrder2MapperProfile(IMappingEngine mappingEngine)
{
this.CurrentMappingEngine = mappingEngine;
}
protected override void Configure()
{
this.CreateMap<Domain.Order, Domain.Order>()
.WithProfile("Profile002")
.ForMember(dest => dest.Code, opt => opt.MapFrom(source => System.Guid.Empty))
.ForMember(dest => dest.OrderLines, opt => opt.Ignore())
.AfterMap((source, destination) =>
{
foreach (var line in source.OrderLines)
{
destination.AddOrderLine(this.CurrentMappingEngine.Map<Domain.OrderLine, Domain.OrderLine>(line));
}
});
this.CreateMap<Domain.OrderLine, Domain.OrderLine>()
.ForMember(dest => dest.Order, opt => opt.Ignore())
.ForMember(dest => dest.Code, opt => opt.MapFrom(source => System.Guid.Empty));
}
}
And use the current engine here:
destination.AddOrderLine(this.CurrentMappingEngine.Map<Domain.OrderLine, Domain.OrderLine>(line));
QUESTION:
Is this the only possible solution or there are better alternatives?
Am I doing things the proper way?
If someone is interested I've created a github repository which uses StructureMap as a test case.