2012-11-12 37 views
6

我想使用AutoMapper來展平多個級別的數組。AutoMapper和展平嵌套數組

考慮下面的源類:

class X { 
    public string A { get; set; } 
    public Y[] B { get; set; } 
} 

class Y { 
    public string C { get; set; } 
    public Z[] D { get; set; } 
} 

class Z { 
    public string E { get; set; } 
    public string F { get; set; } 
} 

而以下目標:

class Destination { 
    public string A { get; set; } 
    public string C { get; set; } 
    public string E { get; set; } 
    public string F { get; set; } 
} 

我想什麼,能夠做的是從一個或多個X,如獲取列表:

Mapper.Map<IEnumerable<X>, IEnumerable<Destination>>(arrayOfX); 

我無法弄清楚用什麼樣的映射配置來達到這個目的。除非我使用AutoMapper的目標命名約定,MapFrom似乎是1:1組合的方式,但似乎無法處理數組(或其他可枚舉)。

有關如何實現此目的的任何見解?

回答

8

試試這個映射器,

Mapper.CreateMap<Z, Destination>(); 
Mapper.CreateMap<Y, Destination>(); 
Mapper.CreateMap<X, Destination>() 
    .ForMember(destination => destination.A, options => options.MapFrom(source => source.A)).IgnoreAllNonExisting() 
    .ForMember(destination => destination.C, options => options.MapFrom(source => Mapper.Map<IEnumerable<Y>, IEnumerable<Destination>>(source.B).FirstOrDefault().C)) 
    .ForMember(destination => destination.E, options => options.MapFrom(source => Mapper.Map<IEnumerable<Z>, IEnumerable<Destination>>(source.B.SelectMany(d => d.D)).FirstOrDefault().E)) 
    .ForMember(destination => destination.F, options => options.MapFrom(source => Mapper.Map<IEnumerable<Z>, IEnumerable<Destination>>(source.B.SelectMany(d => d.D)).FirstOrDefault().F)); 

var result = Mapper.Map<IEnumerable<X>, IEnumerable<Destination>>(arrayOfX); 
+0

這將引發AutoMapperMappingException如果B或D爲null或零長度數組。 X [] arrayOfX = new X [] {new X(){A =「a1」,B = null},new X(){A =「a2」,B = new Y [] {}}}; –

+0

@JayWalker編輯我的帖子。剛剛添加了空檢查。感謝您的發現。 –

3

我前一陣子有一個非常類似的問題。我收集了一些地點,每個地點都有一些街道。我想將它們映射到一個視圖模型集合,其中每個視圖模型都代表一條街道(包括位置詳細信息)。

這是我的解決方案:https://groups.google.com/forum/#!topic/automapper-users/b66c1M8eS8E

對於這個特定的問題,這可能是你映射配置:

public static class AutoMapperConfig 
{ 
    public static void Configure() 
    { 
     Mapper.CreateMap<Z, Destination>() 
      .ForMember(dest => dest.A, opt => opt.Ignore()) 
      .ForMember(dest => dest.C, opt => opt.Ignore()); 

     Mapper.CreateMap<Y, Destination>() 
      .ForMember(dest => dest.A, opt => opt.Ignore()) 
      .ForMember(dest => dest.E, opt => opt.Ignore()) 
      .ForMember(dest => dest.F, opt => opt.Ignore()); 

     Mapper.CreateMap<X, Destination>() 
      .ForMember(dest => dest.C, opt => opt.Ignore()) 
      .ForMember(dest => dest.E, opt => opt.Ignore()) 
      .ForMember(dest => dest.F, opt => opt.Ignore()); 
    } 
} 

因爲AutoMapper主要是一個1:1的映射,你需要實現一丁點的魔法映射到多個對象。這是你如何能調用映射來填充你的對象一個例子:

​​

這裏有一對夫婦的單元測試,以驗證映射,並顯示在行動:

[TestFixture] 
public class MapperTests 
{ 
    [Test] 
    public void Mapping_Configuration_IsValid() 
    { 
     AutoMapperConfig.Configure(); 
     Mapper.AssertConfigurationIsValid(); 
    } 

    [Test] 
    public void Mapping_TestItems_MappedOK() 
    { 
     AutoMapperConfig.Configure(); 
     Mapper.AssertConfigurationIsValid(); 

     var data = new[] 
      { 
       new X 
        { 
         A = "A1", 
         B = new[] 
          { 
           new Y 
            { 
             C = "A1C1", 
             D = new[] 
              { 
               new Z 
                { 
                 E = "A1C1E1", 
                 F = "A1C1F1" 
                }, 
               new Z 
                { 
                 E = "A1C1E2", 
                 F = "A1C1F2" 
                }, 
              } 
            }, 
           new Y 
            { 
             C = "A1C2", 
             D = new[] 
              { 
               new Z 
                { 
                 E = "A1C2E1", 
                 F = "A1C2F1" 
                }, 
               new Z 
                { 
                 E = "A1C2E2", 
                 F = "A1C2F2" 
                }, 
              } 
            } 
          } 
        } 
      }; 

     var rc = data.SelectMany(
      x => x.B.SelectMany(
       y => y.D 
        .Select(Mapper.Map<Z, Destination>) 
        .Select(z => Mapper.Map(y, z)) 
       ) 
       .Select(y => Mapper.Map(x, y)) 
      ); 

     Assert.That(rc, Is.Not.Null); 
     Assert.That(rc.Count(), Is.EqualTo(4)); 
     var item = rc.FirstOrDefault(x => x.F == "A1C2F2"); 
     Assert.That(item, Is.Not.Null); 
     Assert.That(item.A, Is.EqualTo("A1")); 
     Assert.That(item.C, Is.EqualTo("A1C2")); 
     Assert.That(item.E, Is.EqualTo("A1C2E2")); 
     Assert.That(item.F, Is.EqualTo("A1C2F2")); 
    } 
}