2012-10-29 59 views
4

我想在兩個對象列表之間進行映射。源類型具有A類型的複雜屬性;目標類型是類型爲A的扁平化子集加上源類型中的附加標量屬性。AutoMapper是否可以隱式地展平這個映射?

public class A 
{ 
    public int Id { get; set; } 
    public string Name { get; set; } 
} 

public class Source 
{ 
    public A MyA { get; set; } 
    public int SomeOtherValue { get; set; } 
} 

public class Destination 
{ 
    public string Name { get; set; } 
    public int SomeOtherValue { get; set; } 
} 

如果它是不明確的,我想Source.MyA.Name映射到Destination.NameSource.SomeOtherValue映射到Destination.SomeOtherValue

實際上,類型A有十幾個屬性,其中約80%映射到Destination中的同名屬性。我能得到的東西的工作,如果我明確地拼出映射在CreateMap像這樣:

CreateMap<Source, Destination>() 
    .ForMember(dest => dest.Name, opt => opt.MapFrom(src => src.MyA.Name)); 

這裏的缺點是我想避免添加ForMember線每個A的性能需要得到複製到Destination。我希望我可以做這樣的事情:

CreateMap<Source, Destination>() 
    .ForMember(dest => dest, opt => opt.MapFrom(src => src.MyA)); 

但是,如果我嘗試了上面我得到的,如果映射會註冊一個運行時錯誤:「爲成員自定義配置僅支持頂級個人會員的類型「。

感謝

回答

0

您也可以使用自定義類型轉換器附加屬性的目標類型,以避免遞歸一種解決方法。

[TestFixture] 
public class MapComplexType 
{ 
    [Test] 
    public void Map() 
    { 
     Mapper.CreateMap<A, Destination>(); 

     Mapper.CreateMap<Source, Destination>().ConvertUsing(new TypeConvertor()); 
     var source = new Source 
         { 
          MyA = new A 
             { 
              Name = "Name" 
             }, 
             SomeOtherValue = 5 
         }; 
     var dest = new Destination(); 
     Mapper.Map(source, dest); 
     Assert.AreEqual(dest.Name, "Name"); 
    } 
} 

public class TypeConvertor : ITypeConverter<Source, Destination> 
{ 
    public Destination Convert(ResolutionContext context) 
    { 
     var destination = (Destination) context.DestinationValue; 
     if (!((Destination)context.DestinationValue).IsMapped || destination == null) 
     { 
      destination = destination ?? new Destination(); 
      destination.IsMapped = true; // To avoid recursion 
      Mapper.Map((Source)context.SourceValue, destination); 
          destination.IsMapped = false; // If you want to map the same object few times 
     } 
     Mapper.Map(((Source)context.SourceValue).MyA, destination); 
     return (Destination)context.DestinationValue; 
    } 
} 

public class A 
{ 
    public int Id { get; set; } 
    public string Name { get; set; } 
} 

public class Source 
{ 
    public A MyA { get; set; } 
    public int SomeOtherValue { get; set; } 
} 

public class Destination 
{ 
    public string Name { get; set; } 
    public int SomeOtherValue { get; set; } 
    // Used only for mapping purposes 
    internal bool IsMapped { get; set; } 
} 
5

創建ADestination,和SourceDestination之間的映射,然後使用AfterMap()使用在第二

Mapper.CreateMap<A, Destination>(); 
Mapper.CreateMap<Source, Destination>() 
     .AfterMap((s, d) => Mapper.Map<A, Destination>(s.MyA, d)); 

第一映射,然後使用這樣的:

var res = Mapper.Map<Source, Destination>(new Source { SomeOtherValue = 7, MyA = new A { Id = 1, Name = "SomeName" } }); 
+1

此解決方案的問題是Mapper.AssertConfigurationIsValid()將失敗。 – Schneider

0

嘗試這個,

Mapper.CreateMap<A, Destination>(); 
Mapper.CreateMap<Source, Destination>() 
    .ForMember(destination => destination.Name, options => options.MapFrom(source => Mapper.Map<A, Destination>(source.MyA).Name)); 

var objSource = new Source { SomeOtherValue = 7, MyA = new A { Id = 1, Name = "SomeName" } }; 
var result = Mapper.Map<Source, Destination>(objSource); 
+0

這個答案對於問題的解決方案有何不同?您的解決方案是否需要多次.MyA這個問題試圖避免的.ForMember調用? –