Reverse Mapping and Unflattening
Starting with 6.1.0, AutoMapper now supports richer reverse mapping support. Given our entities:
public class Order {
public decimal Total { get; set; }
public Customer Customer { get; set; }
}
public class Customer {
public string Name { get; set; }
}
We can flatten this into a DTO:
public class OrderDto {
public decimal Total { get; set; }
public string CustomerName { get; set; }
}
We can map both directions, including unflattening:
var configuration = new MapperConfiguration(cfg => {
cfg.CreateMap<Order, OrderDto>()
.ReverseMap();
});
By calling ReverseMap
, AutoMapper creates a reverse mapping configuration that includes unflattening:
var customer = new Customer {
Name = "Bob"
};
var order = new Order {
Customer = customer,
Total = 15.8m
};
var orderDto = mapper.Map<Order, OrderDto>(order);
orderDto.CustomerName = "Joe";
mapper.Map(orderDto, order);
order.Customer.Name.ShouldEqual("Joe");
Unflattening is only configured for ReverseMap
. If you want unflattening, you must configure Entity
-> Dto
then call ReverseMap
to create an unflattening type map configuration from the Dto
-> Entity
.
Customizing reverse mapping
AutoMapper will automatically reverse map “Customer.Name” from “CustomerName” based on the original flattening. If you use MapFrom, AutoMapper will attempt to reverse the map:
cfg.CreateMap<Order, OrderDto>()
.ForMember(d => d.CustomerName, opt => opt.MapFrom(src => src.Customer.Name))
.ReverseMap();
As long as the MapFrom
path are member accessors, AutoMapper will unflatten from the same path (CustomerName
=> Customer.Name
).
If you need to customize this, for a reverse map you can use ForPath
:
cfg.CreateMap<Order, OrderDto>()
.ForMember(d => d.CustomerName, opt => opt.MapFrom(src => src.Customer.Name))
.ReverseMap()
.ForPath(s => s.Customer.Name, opt => opt.MapFrom(src => src.CustomerName));
For most cases you shouldn’t need this, as the original MapFrom will be reversed for you. Use ForPath when the path to get and set the values are different.
If you do not want unflattening behavior, you can remove the call to ReverseMap
and create two separate maps. Or, you can use Ignore:
cfg.CreateMap<Order, OrderDto>()
.ForMember(d => d.CustomerName, opt => opt.MapFrom(src => src.Customer.Name))
.ReverseMap()
.ForPath(s => s.Customer.Name, opt => opt.Ignore());
IncludeMembers
ReverseMap
also integrates with IncludeMembers
and configuration like
ForMember(destination => destination.IncludedMember, member => member.MapFrom(source => source))