AutoMapper Как Сопоставить Объект A Объекту B По-Разному В Зависимости От Контекста
вызов всех гуру AutoMapper!
Я хотел бы иметь возможность сопоставлять объект A объекту B по-разному в зависимости от контекста во время выполнения. В частности, я хотел бы игнорировать определенные свойства в одном случае отображения и иметь все свойства, отображаемые в другом случае.
то, что я испытываю, это картограф.CreateMap может быть успешно вызван в различных случаях сопоставления, однако после вызова CreateMap карта для определенной пары типов устанавливается и не впоследствии изменено путем последующих вызовов CreateMap, которые могут описывать сопоставление по-разному.
Я нашел сообщение в блоге, которое защищает картографа.Reset () чтобы обойти проблему, однако, статический характер класса Mapper означает, что это только вопрос времени, прежде чем произойдет столкновение и сбой.
есть ли способ сделать это?
думаю, мне нужно позвонить картографу.CreateMap один раз в appdomain, а затем, быть в состоянии вызвать Mapper.Карта с подсказками о какие свойства следует включить / исключить.
прямо сейчас я думаю об изменении исходного кода, написав нестатический класс сопоставления,который содержит экземпляр конфигурации сопоставления. Низкая производительность,но потокобезопасная.
Каковы мои варианты. Что можно сделать? Automapper кажется таким многообещающим.
3 ответов
класс Mapper-это просто тонкая оболочка поверх объектов конфигурации и MappingEngine. Вы можете создавать отдельные экземпляры объектов Configuration / MappingEngine (все еще используя синглеты) и использовать выбранный контейнер IoC для загрузки правильного по мере необходимости.
лучшим вариантом по-прежнему является использование различных типов назначения. Действительно трудная часть о действительно поддержке этой функции-неотъемлемая иерархическая природа карт типов. Объект верхнего уровня может есть профиль отображения, в то время как более низкие уровни не делают. Некоторые между ними, возможно это или нет и т. д.
просто в дополнение к ответу Джимми вот код, необходимый для использования AutoMapper без статического Mapper
начиная с версии 4.2.1 Automapper имеет санкционированный нестатический картограф и конфигурацию (спасибо Джимми!).
var config = new MapperConfiguration(cfg => {
cfg.CreateMap<ClassA, ClassB>();
});
var mapper = config.CreateMapper();
в новых выпусках есть много других полезных опций (например, профили) для создания различных экземпляров mapper. Вы можете получить все подробности в официальная документация
(правильный для версии 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);
для меня это звучит как лучший дизайн, возможно, иметь несколько классов назначения (возможно, наследование от общей базы или реализация общего интерфейса)
Если свойства unmapped никогда не будут использоваться в одном из вариантов, вы можете полностью оставить их (давая гарантию времени компиляции, что они не используются по ошибке), выбросить исключение, когда к ним обращаются (не так хорошо, как гарантия времени компиляции, но иногда вам нужен полный интерфейс реализовано) или даже использовать заменяющее значение.
например:
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 возможность проверки сопоставлений, а затем знать, что каждое свойство в целевых классах будет заполнено.