2010-04-29 3 views
10

Appel à tous les gourous AutoMapper! Je souhaite pouvoir mapper différemment l'objet A à l'objet B en fonction du contexte au moment de l'exécution. En particulier, je voudrais ignorer certaines propriétés dans un cas de mappage et avoir toutes les propriétés mappées dans un autre cas. Ce que j'expérience est que Mapper.CreateMap peut être appelé avec succès dans les différents cas de mappage. Cependant, une fois que CreateMap est appelé, la carte pour une paire particulière de types est définie et n'est pas modifiée par la suite par des appels CreateMap successifs. pourrait décrire la cartographie différemment.AutoMapper Comment mapper l'objet A à l'objet B différemment selon le contexte

J'ai trouvé un billet de blog qui recommande à Mapper.Reset() de contourner le problème, mais la nature statique de la classe Mapper signifie que ce n'est qu'une question de temps avant qu'une collision et un plantage surviennent.

Existe-t-il un moyen de le faire? Ce dont je pense avoir besoin est d'appeler Mapper.CreateMap une fois par appdomain, et plus tard, être capable d'appeler Mapper.Map avec des indications sur les propriétés qui doivent être incluses/exclues.

En ce moment, je pense à changer le code source en écrivant une classe de mappage non statique qui contient l'instance de configuration de mappage basée. Mauvaise performance, mais thread sécurisé.

Quelles sont mes options. Ce qui peut être fait? Automapper semble si prometteur.

+2

@Omu: Vous et votre "ValueInjecter" commencez à être très agaçant. Vous n'avez pas à répondre à chaque question AutoMapper avec votre plugin pour ValueInjecter (si ce n'est pas ValueInjector). Je suis personnellement rebuté par cela, et ne le regarderais même pas à cause de vos tactiques. Ce n'est pas un homme professionnel. – epitka

Répondre

5

La classe Mapper est simplement une enveloppe fine au-dessus d'un objet Configuration et MappingEngine. Vous pouvez créer des instances distinctes d'objets Configuration/MappingEngine (en utilisant toujours des singletons), et utiliser votre conteneur IoC de choix pour charger le bon, si nécessaire.

La meilleure option consiste toujours à utiliser différents types de destination. La partie la plus difficile à propos de la prise en charge de cette fonctionnalité est la nature hiérarchique inhérente aux cartes de type. L'objet de niveau supérieur peut avoir un profil de mappage, tandis que les objets de niveau inférieur ne le sont pas. Certains entre pourraient avoir ou non, etc.

1

Pour moi, cela ressemble à une meilleure conception pourrait être d'avoir plusieurs classes de destination (éventuellement héritant d'une base commune ou la mise en œuvre d'une interface commune)

Si la les propriétés non mappées ne seront jamais utilisées dans l'une des variantes, vous pouvez les omettre entièrement (donner le temps de compilation garantissant qu'elles ne sont pas utilisées par erreur), lancer une exception quand elles sont accédées (pas aussi bonne qu'une garantie de compilation, mais parfois vous avez besoin de l'interface complète pour être implémenté) ou même utiliser une valeur de remplacement.

Par exemple:

public class Source 
{ 
    public string Name {get;set;} 
    public BigEntity {get;set;} 

    /* other members */ 
} 

public class SourceDTO 
{ 
    public string Name {get;set;} 
    public BigEntity {get;set;} 
} 

public class SourceSummaryDTO 
{ 
    public string Name {get;set;} 
} 

Sinon, vous pouvez le faire:

public class SourceSummaryDTO : SourceDTO 
{ 
    public string Name {get;set;} 
    public BigEntity 
    { 
     get{throw new NotSupportedException();} 
     set{throw new NotSupportedException();} 
    } 
} 

De cette façon, vous pouvez passer un SourceSummaryDTO comme si elle était un SourceDTO. Avoir des propriétés conditionnellement peuplées me semble être une recette pour les problèmes - je préfère avoir des classes explicites sur ce qu'elles contiennent, en particulier avec les objets de transfert de données. Pour moi, la meilleure chose à propos d'Automapper est la possibilité de vérifier les mappages et de savoir que toutes les propriétés des classes de destination seront remplies.

13

Juste pour compléter la réponse de Jimmy est ici le code nécessaire pour utiliser AutoMapper sans Mapper statique

de la version 4.2.1 Automapper a un mappeur non statique sanctionné et configuration (merci Jimmy!).

var config = new MapperConfiguration(cfg => { 
    cfg.CreateMap<ClassA, ClassB>(); 
}); 

var mapper = config.CreateMapper(); 

Il existe de nombreuses autres options utiles (telles que les profils) dans les nouvelles versions pour créer différentes instances de mappeur. Vous pouvez obtenir tous les détails dans le official documentation

(correct pour la version 4.1.1)

// Configuration 
AutoMapper.Mappers.MapperRegistry.Reset(); 
var autoMapperCfg = new AutoMapper.ConfigurationStore(new TypeMapFactory(), AutoMapper.Mappers.MapperRegistry.Mappers); 
var mappingEngine = new AutoMapper.MappingEngine(autoMapperCfg); 
autoMapperCfg.Seal(); 

//Usage example 
autoMapperCfg.CreateMap<ClassA, ClassB>(); 

var b = mappingEngine.Map<ClassB>(a); 

(correcte pour la version 3.2.1)

// Configuration 
var platformSpecificRegistry = AutoMapper.Internal.PlatformAdapter.Resolve<IPlatformSpecificMapperRegistry>(); 
platformSpecificRegistry.Initialize(); 

var autoMapperCfg = new AutoMapper.ConfigurationStore(new TypeMapFactory(), AutoMapper.Mappers.MapperRegistry.Mappers); 
var mappingEngine = new AutoMapper.MappingEngine(autoMapperCfg); 

//Usage example 
autoMapperCfg.CreateMap<ClassA, ClassB>(); 

var b = mappingEngine.Map<ClassB>(a); 

(correct pour la version 2.2.1)

// Configuration 
var autoMapperCfg = new AutoMapper.ConfigurationStore(new AutoMapper.TypeMapFactory(), AutoMapper.Mappers.MapperRegistry.AllMappers()); 
var mappingEngine = new AutoMapper.MappingEngine(autoMapperCfg); 

//Usage example 
autoMapperCfg.CreateMap<ClassA, ClassB>(); 

var b = mappingEngine.Map<ClassB>(a); 
Questions connexes