2012-12-21 8 views
12

Czy mogę używać mapowania dziedziczenia w AutoMapper (v2.2) dla map o tym samym typie źródła, ale o różnych typach docelowych?AutoMapper - mapowanie dziedziczenia nie działa, to samo źródło, wiele miejsc docelowych

mam tę podstawową sytuację (prawdziwe zajęcia mają o wiele więcej właściwości):

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 i ViewModelB są różne reprezentacje tej samej klasy Entity:

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

chcę ponownie wykorzystać to samo mapowanie BaseViewModel dla każdego ViewModel, takich jak:

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

Ale niestety to nie działa. Połączenia takie jak:

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

spowodować model po PropertyA odwzorowane, ale nie CommonProperty. Wydaje mi się, że poprawnie śledzę przykłady w https://github.com/AutoMapper/AutoMapper/wiki/Mapping-inheritance, ale obawiam się, że tworzenie wielu map utworzonych za pomocą tego samego typu źródła powoduje automatyczne wywoływanie AutoMappera.

Jakieś spostrzeżenia? Podoba mi się pomysł grupowania mapowania klas Base razem, ale to nie działa.

+1

Dla przyszłych czytelników tego pytania - wygląda na to, że AutoMapper naprawił to, ponieważ pytanie zostało zadane. –

+0

Próbuję zrobić to samo tutaj, ale staram się robić: 'var Model = Mapper.Map (podmiot)' ale to wraca wystąpienie ViewModelA, a nie wystąpienie BaseViewModel, nawet myślę, że mówię funkcji Mapa, aby zwrócić typ BaseViewModel. Używam Automapper 3.0, więc wygląda na to, że oryginalny błąd z wersji 2.2 został rozwiązany. – njkremer

+0

Ten wpis SO pomógł mi w rozwiązaniu problemu i uzyskał pożądany efekt. http://stackoverflow.com/questions/27317719/automapper-how-to-not-repeat-mapping-config-from-complex-type-to-base-class – njkremer

Odpowiedz

14

Niestety w tym przypadku AutoMapper wydaje się rejestrować tylko jedno odwzorowanie klasy potomnej na źródło, ostatnie (ViewModelB). Prawdopodobnie został zaprojektowany do pracy z równoległymi hierarchiami, a nie z jednym typem źródła.

Aby obejść ten problem, można upakować wspólne mapowania w metodę rozszerzenia:

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

i używać go w poszczególnych odwzorowań podklasy:

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 do ponownego użycia kodu! – kdawg

+0

Dzięki, ale nie pracował dla mnie. Czy możesz rzucić okiem na pytanie [Używanie AutoMappera do mapowania klas podstawowych] (http://stackoverflow.com/questions/39425775/using-automapper-to-map-base-classes)? –

+0

@ClintEastwood Twój adres URL nie działa – huoxudong125

0

Yo może zrobić tak jak tutaj

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

Istnieje kod rozszerzenia

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

} 
Powiązane problemy