Map complex type to flat type in AutoMapper

I have a complex object like:

public class BusinessUnit
{
        public TradingDesk TradingDesk { get; }
        public string Division { get; }

        public BusinessUnit(string division, TradingDesk tradingDesk)
        {
            Division = division;
            TradingDesk = tradingDesk;
        }
}

I want to map this to the flat type:

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

I have already configured AutoMapper for TradingDesk :

CreateMap<TradingDesk, Row>().ForMember(vm => vm.TradingDeskName, op => op.MapFrom(src => src.Name));

so the following test is passing:

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

But when I try to map BusinessUnit to Row I am having to reconfigure AutoMapper for TradingDesk as such:

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

I expect that AutoMapper should use the already configured source & destination type mapping when it needs to map TradingDesk to Row while mapping BusinessUnit . This way I can build the configuration from the smallest to the largest type while flattening out a complex object without having to define mapping for each individual member in the flattened type.


实际的语法可能会有所不同,因为我以静态的方式使用AutoMapper,但原理保持不变:

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

First of I think your map for trading desk would be just

CreateMap<TradingDesk, Row>();

If memory serves me right, since your destination member matches source member name when ".' are removed then you do not need to specify it explicitly.

If you change your Row class to this

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

your map would be

CreateMap<BusinessUnit, Row>(); 

If you are never going to map to TradingDesk, then remove that map.

If this is defined in some Profile, you can also say

RecognizePrefixes("TradingDesk"); 

and then you do not need to change your Row class.


If you do not want to create a special converters or property resolvers you can perform the second mapping after the map of the main object, eg:

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

In this case, the object has been mapped without creating a new instance.

链接地址: http://www.djcxy.com/p/6382.html

上一篇: 使用AutoMapper将object1的值复制到object2

下一篇: 在AutoMapper中将复杂类型映射到平面类型