Как использовать 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).

Другие вопросы по тегам