Я пытаюсь поместить вложенные объекты в плоский DTO. Я не контролирую именование ни DTO, ни бизнес-объектов, поэтому переименование / реструктуризация, к сожалению, не представляется возможным.
Вот пример моего случая:
//Domain Objects
public class Order {
public decimal Total { get; set; }
public Customer Customer { get; set; }
}
public class Customer {
public string Name { get; set; }
public Address Address { get; set; }
}
public class Address {
public string Street { get; set; }
public string City { get; set; }
}
//Dtos
public class OrderCustomerDTO {
public decimal Total { get; set; }
public string CustomerName { get; set; }
public string CustomerStreet { get; set; }
public string CustomerCity { get; set; }
}
//Mapping profile
public class MapperProfile : AutoMapper.Profile {
public MapperProfile() {
CreateMap<Order, OrderCustomerDTO>(MemberList.None)
.ForMember(dst => dst.Total, opt => opt.MapFrom(src => src.Total));
CreateMap<Customer, OrderCustomerDTO>(MemberList.None)
.ForMember(dst => dst.CustomerName, opt => opt.MapFrom(src => src.Name));
CreateMap<Address, OrderCustomerDTO>(MemberList.None)
.ForMember(dst => dst.CustomerStreet, opt => opt.MapFrom(src => src.Street))
.ForMember(dst => dst.CustomerCity, opt => opt.MapFrom(src => src.City));
}
}
//Perform mapping
public void MapOrder(IEnumerable<Order> input) {
var config = new MapperConfiguration(cfg => {
cfg.AddProfile<MapperProfile>();
});
var mapper = config.CreateMapper();
var mapped = mapper.Map<IEnumerable<OrderCustomerDTO>>(input);
}
Результатиз этого следует, что заполнен только OrderCustomerDTO.Total, а остальное оставлено в виде нулевых значений.
Я думал что-то вроде связывания карт, поэтому предыдущая карта ссылается на следующую и так далее, ноэто приведет к исключению:
// Invalid map
public class MapperProfile : AutoMapper.Profile {
public MapperProfile() {
CreateMap<Order, OrderCustomerDTO>(MemberList.None)
.ForMember(dst => dst.Total, opt => opt.MapFrom(src => src.Total))
.ForMember(dst => dst, opt => opt.MapFrom(src => src.Customer));//Load nested type
CreateMap<Customer, OrderCustomerDTO>(MemberList.None)
.ForMember(dst => dst.CustomerName, opt => opt.MapFrom(src => src.Name))
.ForMember(dst => dst, opt => opt.MapFrom(src => src.Address)); //Load nested type
CreateMap<Address, OrderCustomerDTO>(MemberList.None)
.ForMember(dst => dst.CustomerStreet, opt => opt.MapFrom(src => src.Street))
.ForMember(dst => dst.CustomerCity, opt => opt.MapFrom(src => src.City));
}
}
Это приведет к созданию исключения, подобного следующему:
Исключение типа 'AutoMapper.AutoMapperConfigurationException' произошло в AutoMapper.dll, но не былообрабатывается в коде пользователя Дополнительная информация: Пользовательская конфигурация для элементов поддерживается только для отдельных элементов верхнего уровня для типа.
Очевидно, что я что-то упускаю из-за этих вложенных отображений. Решение (уродливое) состоит в том, чтобы собрать все это в одну Карту, но это означает, что у меня будет что-то вроде:
// Ugly map
public class MapperProfile : AutoMapper.Profile {
public MapperProfile() {
CreateMap<Order, OrderCustomerDTO>(MemberList.None)
.ForMember(dst => dst.Total, opt => opt.MapFrom(src => src.Total))
.ForMember(dst => dst.CustomerName, opt => opt.MapFrom(src => src.Customer.Name))
.ForMember(dst => dst.CustomerStreet, opt => opt.MapFrom(src => src.Customer.Address.Street))
.ForMember(dst => dst.CustomerCity, opt => opt.MapFrom(src => src.Customer.Address.City));
}
}
Понятно, что для такого подхода не нужно многобеспорядок, и полностью не поддерживаемый.
Как я могу отделить карты автоматов каждого вложенного объекта в его собственную карту, и при этом сохранить связь между вложенным объектом и верхним ??