Как использовать Ignore глобально в AutoMapper?
Вот как это выглядит прямо сейчас. DestinationA и DestinationB являются производными от некоторого класса DestinationBase. И мне нужно игнорировать некоторые общие свойства для всех этих производных классов. Есть ли способ применить эти параметры игнорирования глобально, без необходимости повторения для всех производных классов назначения?
Mapper.CreateMap<SourceA, DestinationA>()
.ForMember(d => d.PropA, opt => opt.Ignore())
.ForMember(d => d.PropB, opt => opt.Ignore())
.ForMember(d => d.PropC, opt => opt.Ignore());
Mapper.CreateMap<SourceB, DestinationB>()
.ForMember(d => d.PropA, opt => opt.Ignore())
.ForMember(d => d.PropB, opt => opt.Ignore())
.ForMember(d => d.PropC, opt => opt.Ignore());
Я ожидаю что-то вроде этого:
Mapper.CreateMap<DestinationBase>().ForAllSource()
.ForMember(d => d.PropA, opt => opt.Ignore())
.ForMember(d => d.PropB, opt => opt.Ignore())
.ForMember(d => d.PropC, opt => opt.Ignore());
4 ответа
Вы можете игнорировать все несопоставленные свойства глобально. Несмотря на то, что это противоречит главному преимуществу automapper, позволяет делать только явное отображение: это для Automapper 6:
var mapperConfiguration = new MapperConfiguration(cfg =>
{
cfg.AddProfile(new MyProfile());
// ignore all unmapped properties globally
cfg.ForAllMaps((map, exp) => exp.ForAllOtherMembers(opt => opt.Ignore()));
});
Теперь есть метод FindTypeMapFor, который делает этот метод расширения еще меньше (и более эффективным?):
public static IMappingExpression<TSource, TDestination> IgnoreAllNonMapped<TSource, TDestination>(this IMappingExpression<TSource, TDestination> expression)
{
foreach (var property in Mapper.FindTypeMapFor<TSource, TDestination>().GetUnmappedPropertyNames())
{
expression.ForMember(property, opt => opt.Ignore());
}
return expression;
}
У меня была та же проблема, и я наткнулся на этот старый вопрос, когда искал помощи. Я пришел к следующему решению. Может быть, это полезно для кого-то еще...
У меня есть несколько классов, полученных из базового класса. Я хочу исключить свойство этого базового класса из всех отображений любого класса, производного от базового. После создания моих отображений (и без указания каких-либо параметров игнорирования) я делаю это:
foreach(var map in Mapper.GetAllTypeMaps())
{
if (typeof(MyBaseClass).IsAssignableFrom(map.DestinationType))
{
var propInfo = map.DestinationType.GetProperty("PropertyToIgnore");
if (propInfo != null) {
map.FindOrCreatePropertyMapFor(new AutoMapper.Impl.PropertyAccessor(propInfo)).Ignore();
}
}
}
Это немного грубая сила, потому что я должен пройтись по всем картам типов, но он выполняет свою работу.
edit: добавлен пропущенный {в оператор if
Смотрите расширение IgnoreAllNonExisting() по schdr здесь:
AutoMapper: "Игнорировать все остальное"?
public static IMappingExpression<TSource, TDestination>
IgnoreAllNonExisting<TSource, TDestination>(this IMappingExpression<TSource, TDestination> expression)
{
var sourceType = typeof (TSource);
var destinationType = typeof (TDestination);
var existingMaps = Mapper.GetAllTypeMaps().First(x => x.SourceType.Equals(sourceType) && x.DestinationType.Equals(destinationType));
foreach (var property in existingMaps.GetUnmappedPropertyNames())
{
expression.ForMember(property, opt => opt.Ignore());
}
return expression;
}
Использование:
Mapper.CreateMap<SourceType, DestinationType>()
.IgnoreAllNonExisting();
Я не уверен, в какой версии добавлены атрибуты, но в наши дни это можно сделать. Документы.
[Ignore]
public string Property { get; set; }
Проблема с этим подходом заключается в том, что вы пропускаете реализацию AutoMapper по объектам домена, что не очень хорошо.
Кажется, лучший подход - настроить фильтрацию на MapperConfiguration
глобально, определив свой собственный ShouldMapProperty
делегировать или привязать условие к реализации по умолчанию. Документы.
var configuration = new MapperConfiguration(cfg =>
{
cfg.ShouldMapField = ...;
cfg.ShouldMapProperty = ...;
});
Реализации по умолчанию на момент написания здесь. В частности,ShouldMapProperty
возвращается, если не указано p => p.IsPublic()
. Так ты мог бы сделатьp => p.IsPublic() && p.DeclaringType != typeof(SomeBaseType) && p.Name == nameof(SomeBaseType.SomePropertyToIgnore)
.