Карта сложного типа для плоского типа в AutoMapper
У меня есть сложный объект вроде:
public class BusinessUnit
{
public TradingDesk TradingDesk { get; }
public string Division { get; }
public BusinessUnit(string division, TradingDesk tradingDesk)
{
Division = division;
TradingDesk = tradingDesk;
}
}
Я хочу сопоставить это с плоским типом:
public class Row
{
//TradingDesk properties
public string TraderFirstName { get; set; }
public string TraderLastName { get; set; }
public string TradingDeskName { get; set; }
public string Division { get; set; }
}
Я уже настроил AutoMapper
для TradingDesk
:
CreateMap<TradingDesk, Row>().ForMember(vm => vm.TradingDeskName, op => op.MapFrom(src => src.Name));
так что следующий тест проходит:
[Test]
public void Should_Map_TradingDesk_To_Row()
{
var tradingDesk = Fixture.Create<TradingDesk>();
var mapped = AutoMapper.Map<Row>(tradingDesk);
mapped.TradingDeskName.Should()
.Be(tradingDesk.Name);
mapped.TraderFirstName.Should()
.Be(tradingDesk.Trader.FirstName);
mapped.TraderLastName.Should()
.Be(tradingDesk.Trader.LastName);
}
Но когда я пытаюсь сопоставить BusinessUnit
с Row
, мне приходится переконфигурировать AutoMapper
для TradingDesk
как таковой:
CreateMap<BusinessUnit, Row>()
.ForMember(vm => vm.TradingDeskName, op => op.MapFrom(src => src.TradingDesk.Name))
.ForMember(vm => vm.TraderFirstName, op => op.MapFrom(src => src.TradingDesk.Trader.FirstName))
.ForMember(vm => vm.TraderLastName, op => op.MapFrom(src => src.TradingDesk.Trader.LastName));
Я ожидаю, что AutoMapper
должен использовать уже настроенное сопоставление источника и целевого типа, когда ему нужно сопоставить TradingDesk
с Row
при отображении BusinessUnit
. Таким образом, я могу построить конфигурацию от наименьшего до самого большого типа, сглаживая сложный объект без необходимости определять отображение для каждого отдельного элемента в сплющенном типе.
Ответы
Ответ 1
Фактический синтаксис может отличаться, потому что я использую AutoMapper статическим образом, но принцип остается тем же:
Mapper.CreateMap<BusinessUnit, Row>()
.ConvertUsing(source => Mapper.Map<TradingDesk, Row>(source.TradingDesk));
Ответ 2
Сначала я думаю, что ваша карта для торгового стола будет просто
CreateMap<TradingDesk, Row>();
Если память мне подходит, так как ваш участник-получатель соответствует имени члена-источника, когда "." удаляются, тогда вам не нужно явно указывать его.
Если вы измените свой класс Row на этот
public class Row
{
//TradingDesk properties
public string TradingDeskTraderFirstName { get; set; }
public string TradingDeskTraderLastName { get; set; }
public string TradingDeskName { get; set; }
public string Division { get; set; }
}
ваша карта будет
CreateMap<BusinessUnit, Row>();
Если вы никогда не собираетесь сопоставлять с TradingDesk, удалите эту карту.
Если это определено в каком-либо профиле, вы также можете сказать
RecognizePrefixes("TradingDesk");
и вам не нужно менять класс Row.
Ответ 3
Если вы не хотите создавать специальные преобразователи или преобразователи свойств, вы можете выполнить второе сопоставление после карты основного объекта, например:
Mapper.Initialize(cfg =>
{
cfg.CreateMap<TradingDesk, Row>()
.ForMember(vm => vm.TradingDeskName, op => op.MapFrom(src => src.Name));
cfg.CreateMap<BusinessUnit, Row>()
.AfterMap((businessUnit, row) => { Mapper.Map(businessUnit.TradingDesk, row); });
});
var source = new BusinessUnit("division", new TradingDesk { TraderFirstName = "FirstName", TraderLastName = "LastName", Name = "DeskName" });
var dest = Mapper.Map<Row>(source);
В этом случае объект был отображен без создания нового экземпляра.