2010-04-29 1 views
10

Вызов всех гуру AutoMapper!AutoMapper Как скопировать объект A в объект B, в зависимости от контекста

Я хотел бы иметь возможность сопоставлять объект A с объектом B по-разному в зависимости от контекста во время выполнения. В частности, я хотел бы игнорировать некоторые свойства в одном случае отображения и иметь все свойства, отображаемые в другом случае.

То, что я испытываю, заключается в том, что Mapper.CreateMap можно успешно вызвать в разных случаях отображения, однако, как только CreateMap вызывается, карта для определенной пары типов задана и впоследствии не изменяется с помощью последующих вызовов CreateMap, которые может описывать отображение по-разному.

Я нашел сообщение в блоге, которое защищает Mapper.Reset(), чтобы обойти проблему, однако статическая природа класса Mapper означает, что это только вопрос времени, прежде чем произойдет столкновение и сбой.

Есть ли способ сделать это?

Мне кажется, что мне нужно вызвать Mapper.CreateMap один раз за приложение, а позже можно вызвать Mapper.Map с подсказками о том, какие свойства должны быть включены/исключены.

Прямо сейчас, я подумываю об изменении исходного кода, написав класс нестатического сопоставления, содержащий шаблон экземпляра сопоставления. Плохая производительность, но потокобезопасная.

Какие у меня варианты. Что может быть сделано? Automapper кажется таким многообещающим.

+2

@Omu: Вы и ваш «ValueInjecter» начинаете очень раздражать. Вы не должны отвечать на каждый вопрос AutoMapper своим плагином для ValueInjecter (если это не ValueInjector). Я лично отключен этим, и даже не посмотрю на это из-за вашей тактики. Это просто не профессиональный человек. – epitka

ответ

5

Класс Mapper - это всего лишь тонкая оболочка поверх объектов Configuration и MappingEngine. Вы можете создавать отдельные экземпляры объектов Configuration/MappingEngine (по-прежнему используя одиночные точки) и использовать ваш контейнер IoC по выбору для правильной загрузки нужного.

Лучшим вариантом является использование разных типов назначения. Очень сложная часть, действительно поддерживающая эту функцию, - это присущая иерархическая природа карт типов. Объект верхнего уровня может иметь профиль сопоставления, а нижний уровень - нет. Некоторые между могли бы иметь его или нет, и т.д.

1

Для меня это звучит как лучший дизайн может быть иметь несколько классов назначения (возможно наследование от общей базы или реализующие общий интерфейс)

Если unmapped properties никогда не будут использоваться в одном из вариантов, вы можете полностью исключить их (предоставляя время компиляции, чтобы они не использовались по ошибке), генерируют исключение, когда к ним обращаются (не так хорошо, как гарантия времени компиляции, но иногда вам нужен полный интерфейс для реализации) или даже использовать заменяющее значение.

Например:

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

В качестве альтернативы, вы можете сделать это:

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

Таким образом, вы могли бы пройти SourceSummaryDTO, как если бы это был SourceDTO.

Наличие свойств условно заселенных звуков, как рецепт для меня, - я бы предпочел, чтобы классы были явными в отношении того, что они содержат, особенно с объектами передачи данных.

Для меня самое лучшее в Automapper - это возможность проверить сопоставления, а затем знать, что каждое свойство в классах назначения будет заполнено.

13

Просто в дополнение ответ Джимми вот код, необходимый для использования AutoMapper без статического Mapper

В версии 4.2.1 Automapper имеет санкционированный нон статического картографа и конфигурации (спасибо Джимми!).

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

var mapper = config.CreateMapper(); 

В новых выпусках есть много других полезных опций (таких как профили) для создания разных экземпляров картпера. Вы можете получить все детали в official documentation

(для версии 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); 

(для версии 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); 

(исправить для версии 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);