2010-04-29 18 views
10

¡Llamando a todos los gurús de AutoMapper!AutoMapper Cómo asignar el objeto A al objeto B de forma diferente según el contexto

Me gustaría poder asignar el objeto A al objeto B de forma diferente según el contexto en el tiempo de ejecución. En particular, me gustaría ignorar ciertas propiedades en un caso de mapeo, y tener todas las propiedades mapeadas en otro caso.

Lo que estoy experimentando es que Mapper.CreateMap se puede llamar con éxito en los diferentes casos de mapeo; sin embargo, una vez que se llama CreateMap, se establece el mapa para un par particular de tipos y no se cambia posteriormente mediante llamadas a CreateMap podría describir el mapeo de manera diferente.

Encontré una publicación de blog que recomienda Mapper.Reset() para eludir el problema, sin embargo, la naturaleza estática de la clase Mapper significa que es solo cuestión de tiempo antes de que ocurra una colisión y un bloqueo.

¿Hay alguna manera de hacerlo?

Lo que creo que necesito es llamar a Mapper.CreateMap una vez por appdomain, y luego, poder llamar a Mapper.Map con pistas sobre qué propiedades deben incluirse/excluirse.

En este momento, estoy pensando en cambiar el código fuente escribiendo una clase de asignación no estática que contiene la instancia de configuración de asignación basada. Pobre rendimiento, pero seguro para subprocesos.

¿Cuáles son mis opciones? ¿Qué se puede hacer? Automapper parece tan prometedor.

+2

@Omu: Usted y su "ValueInjecter" comienzan a ser muy molestos. No tiene que responder cada pregunta de AutoMapper con su complemento para ValueInjecter (si no fuera ValueInjector). Estoy personalmente desconectado por esto, y ni siquiera lo miraría debido a tus tácticas. Simplemente no es un hombre profesional. – epitka

Respuesta

5

La clase Mapper es simplemente una envoltura delgada encima de los objetos Configuration y MappingEngine. Puede crear instancias separadas de objetos de Configuración/MappingEngine (aún usando singletons), y usar su contenedor IoC de elección para cargar el correcto según sea necesario.

La mejor opción es usar diferentes tipos de destino. La parte realmente difícil de apoyar realmente esta característica es la naturaleza jerárquica inherente de los mapas tipo. El objeto de nivel superior puede tener un perfil de asignación, mientras que los de nivel inferior no. Algunos en el medio puede tener o no, etc.

1

Para mí, suena como un mejor diseño podría ser la de tener varias clases de destino (posiblemente heredan de una base común o que implementan una interfaz común)

Si el las propiedades no asignadas nunca se usarán en una de las variaciones, se pueden omitir por completo (dando tiempo de compilación, garantizar que no se usen por error), lanzar una excepción cuando se acceda (no tan buena como una garantía de tiempo de compilación, pero a veces necesitas que se implemente la interfaz completa) o incluso usar un valor sustituto.

Por ejemplo:

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

Alternativamente, usted puede hacer esto:

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

De esta manera, se puede pasar un SourceSummaryDTO como si fuera un SourceDTO.

Tener las propiedades condicionalmente pobladas me suena como una receta de problemas. Prefiero tener clases que sean explícitas sobre lo que contienen, especialmente con los objetos de Data Transfer.

Para mí, lo mejor de Automapper es la capacidad de verificar las asignaciones y saber que se completarán todas las propiedades en las clases de destino.

13

Sólo para complementar la respuesta de Jimmy aquí está el código necesario para utilizar AutoMapper sin el asignador estática

partir de la versión 4.2.1 AutoMapper tiene un mapeador estática no sancionada y la configuración (gracias Jimmy!).

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

var mapper = config.CreateMapper(); 

Hay muchas otras opciones útiles (como perfiles) en las nuevas versiones para crear diferentes instancias de correlacionador. Usted puede obtener todos los detalles en el official documentation

(correctas para la versión 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); 

(correctas para la versión 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); 

(correcto para la versión 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); 
Cuestiones relacionadas