在AutoMapper中将复杂类型映射为扁平类型

12

我有一个像这样的复杂对象:

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; }
}

我已经为 TradingDesk 配置了 AutoMapper

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时,应该使用已配置的源和目标类型映射。这样,我可以从最小的类型开始构建配置,一步步展开复杂对象,而不必为平展后的每个成员定义映射。

3个回答

1

实际语法可能会有所不同,因为我是以静态方式使用AutoMapper,但原则仍然相同:

Mapper.CreateMap<BusinessUnit, Row>()
      .ConvertUsing(source => Mapper.Map<TradingDesk, Row>(source.TradingDesk));

但是我没有从那里创建的“IMapper”实例; 因此,您的代码会出现“AutoMapperMappingException”错误。 - aateeque
这篇帖子来看,如果你不依赖静态Mapper,你的选择可能会受到限制。 - Alexandru Marculescu

0

首先,我认为您的交易台地图只是...

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类了。


0
如果您不想创建特殊的转换器或属性解析器,可以在主对象映射之后执行第二个映射,例如:
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);

在这种情况下,对象已经被映射而无需创建新实例。

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接