2012-12-21 13 views
12

È possibile utilizzare la mappatura di ereditarietà in AutoMapper (v2.2) per le mappe con lo stesso tipo di origine ma tipi di destinazione diversi?AutoMapper - mapping di ereditarietà non funzionante, stessa origine, più destinazioni

ho questa situazione di base (le classi reali hanno molte proprietà):

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 e ViewModelB sono diverse rappresentazioni della stessa classe Entity:

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

voglio riutilizzare il stessa mappatura per BaseViewModel per ogni ViewModel, ad esempio:

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

Ma sfortunatamente, questo non sembra funzionare. Chiamate come questi:

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

risultato in model aver PropertyA mappati, ma non CommonProperty. Credo che sto seguendo gli esempi in https://github.com/AutoMapper/AutoMapper/wiki/Mapping-inheritance correttamente, ma temo che avere più mappe create con lo stesso tipo di sorgente stia facendo scattare AutoMapper.

Eventuali approfondimenti? Mi piace l'idea di raggruppare insieme i mapping delle classi base, ma non sembra funzionare.

+1

Per i futuri lettori di questa domanda - sembra che AutoMapper abbia risolto questo problema dal momento in cui è stata posta la domanda. –

+0

Sto cercando di fare la stessa cosa qui, ma sto cercando di fare: 'var model = Mapper.Map (entità)' ma restituisce un'istanza di ViewModelA, non un istanza di BaseViewModel, anche pensato che sto dicendo alla funzione Map per restituire un tipo BaseViewModel. Sto usando Automapper 3.0 così, sembra che il bug originale di 2.2 sia stato risolto. – njkremer

+0

Questo post SO mi ha aiutato con il mio problema e ha ottenuto l'effetto desiderato per funzionare. http://stackoverflow.com/questions/27317719/automapper-how-to-not-repeat-mapping-config-from-complex-type-to-base-class – njkremer

risposta

14

Sfortunatamente in questo caso, AutoMapper sembra registrare solo una mappatura classe figlio per tipo di origine, l'ultima (ViewModelB). Probabilmente è stato progettato per funzionare con gerarchie parallele, non con un singolo tipo di sorgente.

Per risolvere questo problema, è possibile incapsulare le mappature comuni a un metodo di estensione:

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

e utilizzarlo nelle singole mappature sottoclasse:

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 per il riutilizzo del codice! – kdawg

+0

Grazie ma non ha funzionato per me. Potresti dare un'occhiata a [Utilizzo di AutoMapper per mappare le classi di base] (http://stackoverflow.com/questions/39425775/using-automapper-to-map-base-classes) domanda? –

+0

@ClintEastwood l'URL non funziona – huoxudong125

0

Yo può fare come qui

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

C'è il codice dell'estensione

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

}