2012-12-21 10 views
12

Kann ich die Vererbungszuordnung in AutoMapper (v2.2) für Karten mit demselben Quellentyp aber unterschiedlichen Zieltypen verwenden?AutoMapper - Vererbungszuordnung funktioniert nicht, gleiche Quelle, mehrere Ziele

Ich habe diese Grundsituation (die realen Klassen viele weitere Eigenschaften haben):

public abstract class BaseViewModel 
{ 
    public int CommonProperty { get; set;} 
} 

public class ViewModelA : BaseViewModel 
{ 
    public int PropertyA { get; set; } 
} 

public class ViewModelB : BaseViewModel 
{ 
    public int PropertyB { get; set; } 
} 

ViewModelA und ViewModelB unterschiedliche Darstellungen derselben Entity Klasse sind:

public class Entity 
{ 
    public int Property1 { get; set; } 
    public int Property2 { get; set; } 
    public int Property3 { get; set; } 
} 

ich die wiederverwendet werden soll gleiche Abbildung für BaseViewModel für jedes ViewModel, wie zum Beispiel:

Mapper.CreateMap<Entity, BaseViewModel>() 
    .Include<Entity, ViewModelA>() 
    .Include<Entity, ViewModelB>() 
    .ForMember(x => x.CommonProperty, y => y.MapFrom(z => z.Property1)); 

Mapper.CreateMap<Entity, ViewModelA>() 
    .ForMember(x => x.PropertyA, y => y.MapFrom(z => z.Property2)); 

Mapper.CreateMap<Entity, ViewModelB>() 
    .ForMember(x => x.PropertyB, y => y.MapFrom(z => z.Property3)); 

Aber leider scheint das nicht zu funktionieren. Anrufe wie diese:

var model = Mapper.Map<Entity, ViewModelA>(entity); 

Ergebnis in model haben PropertyA abgebildet, aber nicht CommonProperty. Ich glaube, ich befolge die Beispiele in https://github.com/AutoMapper/AutoMapper/wiki/Mapping-inheritance richtig, aber ich habe Angst, mehrere Karten erstellt mit dem gleichen Quellentyp ist AutoMapper ausstoßen.

Irgendwelche Einsichten? Ich mag die Idee, Basisklassenzuordnungen zu gruppieren, aber das scheint nicht zu funktionieren.

+1

Für zukünftige Leser dieser Frage - es scheint, AutoMapper hat dies behoben, seit die Frage gestellt wurde. –

+0

Ich versuche, das gleiche hier zu tun, aber ich versuche zu tun: 'var model = Mapper.Map (Einheit)' aber es gibt eine Instanz von ViewModelA, nicht eine Instanz von BaseViewModel, auch wenn ich der Map-Funktion sage, dass sie einen BaseViewModel-Typ zurückgibt. Ich benutze Automapper 3.0 so, es scheint, als ob der ursprüngliche Fehler von 2.2 behoben wurde. – njkremer

+0

Diese SO-Post hat mir bei meinem Problem geholfen und den gewünschten Effekt erzielt. http://stackoverflow.com/questions/27317719/automapper-how-to-not-repeat-mapping-config-from-complex-type-to-base-class – njkremer

Antwort

14

Leider scheint AutoMapper nur eine Kindklassenzuordnung pro Quellentyp zu registrieren, die letzte (ViewModelB). Dies wurde wahrscheinlich entwickelt, um mit parallelen Hierarchien und nicht mit einem einzelnen Quelltyp zu arbeiten.

Um dies zu umgehen, können Sie die gemeinsame Zuordnungen in einer Erweiterungsmethode kapseln:

public static IMappingExpression<Entity, TDestination> MapBaseViewModel<TDestination>(this IMappingExpression<Entity, TDestination> map) 
    where TDestination : BaseViewModel { 
    return map.ForMember(x => x.CommonProperty, y => y.MapFrom(z => z.Property1)); 
} 

Und es in den einzelnen Unterklasse Zuordnungen verwenden:

Mapper.CreateMap<Entity, ViewModelA>() 
    .MapBaseViewModel<ViewModelA>() 
    .ForMember(x => x.PropertyA, y => y.MapFrom(z => z.Property2)); 

Mapper.CreateMap<Entity, ViewModelB>() 
    .MapBaseViewModel<ViewModelB>() 
    .ForMember(x => x.PropertyB, y => y.MapFrom(z => z.Property3)); 
+4

+1 für Code-Wiederverwendung! – kdawg

+0

Danke aber nicht für mich gearbeitet. Könnten Sie bitte einen Blick auf [Verwenden von AutoMapper zum Zuordnen von Basisklassen] (http://stackoverflow.com/questions/39425775/using-automapper-to-map-base-classes) Frage? –

+0

@ClintEastwood Ihre URL funktioniert nicht – huoxudong125

0

Yo wie hier tun kann

  CreateMap<Entity, ViewModelA>() 
      .InheritMapping(x => 
      { 
       x.IncludeDestinationBase<BaseViewModel>(); 
      }); 

Es gibt einen Code der Erweiterung

public static class MapExtensions 
{   

    public static void InheritMapping<TSource, TDestination>(
     this IMappingExpression<TSource, TDestination> mappingExpression, 
     Action<InheritMappingExpresssion<TSource, TDestination>> action) 
    { 
     InheritMappingExpresssion<TSource, TDestination> x = 
      new InheritMappingExpresssion<TSource, TDestination>(mappingExpression); 
     action(x); 
     x.ConditionsForAll(); 
    } 

    private static bool NotAlreadyMapped(Type sourceType, Type desitnationType, ResolutionContext r, Type typeSourceCurrent, Type typeDestCurrent) 
    { 
     var result = !r.IsSourceValueNull && 
       Mapper.FindTypeMapFor(sourceType, desitnationType).GetPropertyMaps().Where(
        m => m.DestinationProperty.Name.Equals(r.MemberName)).Select(y => !y.IsMapped() 
        ).All(b => b); 
     return result; 
    } 
    public class InheritMappingExpresssion<TSource, TDestination> 
    { 
     private readonly IMappingExpression<TSource, TDestination> _sourcExpression; 
     public InheritMappingExpresssion(IMappingExpression<TSource, TDestination> sourcExpression) 
     { 
      _sourcExpression = sourcExpression; 
     } 
     public void IncludeSourceBase<TSourceBase>(
      bool ovverideExist = false) 
     { 
      Type sourceType = typeof (TSourceBase); 
      Type destinationType = typeof (TDestination); 
      if (!sourceType.IsAssignableFrom(typeof (TSource))) throw new NotSupportedException(); 
      Result(sourceType, destinationType); 
     } 
     public void IncludeDestinationBase<TDestinationBase>() 
     { 
      Type sourceType = typeof (TSource); 
      Type destinationType = typeof (TDestinationBase); 
      if (!destinationType.IsAssignableFrom(typeof (TDestination))) throw new NotSupportedException(); 
      Result(sourceType, destinationType); 
     } 
     public void IncludeBothBases<TSourceBase, TDestinatioBase>() 
     { 
      Type sourceType = typeof (TSourceBase); 
      Type destinationType = typeof (TDestinatioBase); 
      if (!sourceType.IsAssignableFrom(typeof (TSource))) throw new NotSupportedException(); 
      if (!destinationType.IsAssignableFrom(typeof (TDestination))) throw new NotSupportedException(); 
      Result(sourceType, destinationType); 
     } 
     internal void ConditionsForAll() 
     { 
      _sourcExpression.ForAllMembers(x => x.Condition(r => _conditions.All(c => c(r))));//указываем что все кондишены истинны 
     } 
     private List<Func<ResolutionContext, bool>> _conditions = new List<Func<ResolutionContext, bool>>(); 
     private void Result(Type typeSource, Type typeDest) 
     { 
       _sourcExpression.BeforeMap((x, y) => 
       { 
        Mapper.Map(x, y, typeSource, typeDest); 
       }); 
       _conditions.Add((r) => NotAlreadyMapped(typeSource, typeDest, r, typeof (TSource), typeof (TDestination))); 
     } 
    } 

} 
Verwandte Themen