2012-11-12 13 views
6

Ich versuche AutoMapper zu verwenden, um mehrere Ebenen von Arrays zu reduzieren.AutoMapper und Ebenen verschachtelte Arrays

Betrachten Sie die folgende Quellklassen:

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

Und das folgende Ziel:

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

Was Ich mag würde der Lage sein, eine Liste von einem oder mehreren X zu tun ist, erhalten, zB :

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

Ich bin nicht in der Lage herauszufinden, welche Art von Mapping-Konfiguration zu diesem Zweck verwenden. MapFrom scheint der Weg für 1: 1-Kompositionen zu sein, scheint aber nicht in der Lage zu sein, mit dem Array (oder anderen aufzählbaren Elementen) umzugehen, wenn ich nicht die Namenskonvention von AutoMapper verwende.

Irgendwelche Erkenntnisse, wie dies zu erreichen ist?

Antwort

8

diesen Mapper Versuchen,

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

Das wird ein Wurf AutoMapperMappingException, wenn B oder D null oder ein Array nullter Länge ist. X [] ArrayOfX = neues X [] {neues X() {A = "a1", B = null}, neues X() {A = "a2", B = neues Y [] {}}}; –

+0

@JayWalker Hat meinen Beitrag bearbeitet. Habe gerade den Null-Check hinzugefügt. Danke fürs Finden. –

3

hatte ich ein sehr ähnliches vor einer Weile Problem. Ich hatte eine Sammlung von Orten und jeder Ort hatte eine Sammlung von Straßen. Ich wollte sie einer Sammlung von Ansichtsmodellen zuordnen, wobei jedes Ansichtsmodell eine Straße repräsentierte (einschließlich der Standortdetails).

Dies war meine Lösung: https://groups.google.com/forum/#!topic/automapper-users/b66c1M8eS8E

Für dieses besondere Problem, könnte dies Ihre Mapping-Konfiguration sein:

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

Da AutoMapper in erster Linie eine 1: 1-Abbildung, müssen Sie ein kleines bisschen implementieren von Magie, um mehrere Objekte zuzuordnen. Dies ist ein Beispiel dafür, wie Sie diese Zuordnung nennen könnte Ihr Objekt zu füllen:

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

Hier ein paar Unit-Tests sind die Zuordnung zu bestätigen und zeigen es in Aktion:

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