2012-11-12 22 views
6

Próbuję użyć AutoMappera do spłaszczenia wielu poziomów tablic.AutoMapper i spłaszczanie macierzy zagnieżdżonych

Rozważmy następujące klasy źródło:

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

i następujący cel:

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

Co chciałbym być w stanie zrobić, to dostać się lista, z jednego lub więcej X, np :

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

Nie jestem w stanie określić, jakiego rodzaju konfiguracji odwzorowania użyć, aby to osiągnąć. MapFrom wydaje się być sposobem na kompozycje 1: 1, ale wydaje się, że nie jest w stanie obsłużyć tablicy (lub innych przeliczalnych), chyba że używam konwencji nazewnictwa docelowego AutoMappera.

Wszelkie informacje na temat tego, jak to osiągnąć?

Odpowiedz

8

Spróbuj mapowania,

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

To wygeneruje AutoMapperMappingException, jeśli B lub D jest tablicą zerową lub zerową. X [] arrayOfX = nowy X [] {nowy X() {A = "a1", B = null}, nowy X() {A = "a2", B = nowy Y [] {}}}; –

+0

@JayWalker Edytowałem mój wpis. Właśnie dodano kontrolę zerową. Dzięki za znalezienie. –

3

miałem bardzo podobny problem jakiś czas temu. Miałem kolekcję lokacji, a każda lokalizacja miała kolekcję ulic. Chciałem je zmapować do kolekcji modeli widoków, gdzie każdy model widoku reprezentował ulicę (w tym szczegóły lokalizacji).

To było moje rozwiązanie: https://groups.google.com/forum/#!topic/automapper-users/b66c1M8eS8E

Dla tego konkretnego problemu, może to być konfiguracja mapowania:

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

Ponieważ AutoMapper to przede wszystkim 1: 1 mapowanie, trzeba zaimplementować odrobinę magii, aby odwzorować na wiele obiektów. Jest to przykład tego, jak można nazwać to odwzorowanie aby wypełnić swój obiekt:

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

Oto kilka testów jednostkowych do sprawdzania poprawności odwzorowania i pokazać go w akcji:

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