AutoMapper: «Игнорировать остальных»?

Есть ли способ сказать AutoMapper игнорировать все свойства, кроме тех, которые явно отображаются?

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

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

 public static IMappingExpression IgnoreAllNonExisting (this IMappingExpression expression) { var flags = BindingFlags.Public | BindingFlags.Instance; var sourceType = typeof (TSource); var destinationProperties = typeof (TDestination).GetProperties(flags); foreach (var property in destinationProperties) { if (sourceType.GetProperty(property.Name, flags) == null) { expression.ForMember(property.Name, opt => opt.Ignore()); } } return expression; } 

Применение:

 Mapper.CreateMap() .IgnoreAllNonExisting(); 

UPDATE : По-видимому, это работает неправильно, если у вас есть пользовательские сопоставления, потому что они перезаписывают их. Я думаю, он все равно может работать, если сначала вызовет IgnoreAllNonExisting, а затем – пользовательские сопоставления.

У schdr есть решение (в качестве ответа на этот вопрос), которое использует Mapper.GetAllTypeMaps() чтобы выяснить, какие свойства не отображаются и автоматически игнорировать их. Кажется, это более надежное решение.

Я обновил расширение Can Gencer, чтобы не перезаписывать существующие карты.

 public static IMappingExpression IgnoreAllNonExisting(this IMappingExpression 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() .ForMember(prop => x.Property, opt => opt.MapFrom(src => src.OtherProperty)) .IgnoreAllNonExisting(); 

Из того, что я понял, вопрос состоял в том, что в месте назначения есть поля, в которых нет поля отображения в источнике, поэтому вы ищете способы игнорировать те неперечисленные целевые поля.

Вместо внедрения и использования этого метода расширения вы можете просто использовать

 Mapper.CreateMap(MemberList.Source); 

Теперь automapper знает, что ему нужно только подтвердить, что все поля источника сопоставлены, но не наоборот.

Я смог сделать это следующим образом:

 Mapper.CreateMap().ForAllMembers(opt => opt.Ignore()); Mapper.CreateMap().ForMember(/*Do explicit mapping 1 here*/); Mapper.CreateMap().ForMember(/*Do explicit mapping 2 here*/); ... 

Примечание. Я использую AutoMapper v.2.0.

Начиная с AutoMapper 5.0, свойство IMappingExpression исчезло, что означает, что решение 4.2 больше не работает. Я создал решение, которое использует оригинальную функциональность, но с другим синтаксисом:

 var config = new MapperConfiguration(cfg => { cfg.CreateMap(); cfg.IgnoreUnmapped(); // Ignores unmapped properties on all maps cfg.IgnoreUnmapped(); // Ignores unmapped properties on specific map }); // or add inside a profile public class MyProfile : Profile { this.IgnoreUnmapped(); CreateMap(); } 

Реализация:

 public static class MapperExtensions { private static void IgnoreUnmappedProperties(TypeMap map, IMappingExpression expr) { foreach (string propName in map.GetUnmappedPropertyNames()) { if (map.SourceType.GetProperty(propName) != null) { expr.ForSourceMember(propName, opt => opt.Ignore()); } if (map.DestinationType.GetProperty(propName) != null) { expr.ForMember(propName, opt => opt.Ignore()); } } } public static void IgnoreUnmapped(this IProfileExpression profile) { profile.ForAllMaps(IgnoreUnmappedProperties); } public static void IgnoreUnmapped(this IProfileExpression profile, Func filter) { profile.ForAllMaps((map, expr) => { if (filter(map)) { IgnoreUnmappedProperties(map, expr); } }); } public static void IgnoreUnmapped(this IProfileExpression profile, Type src, Type dest) { profile.IgnoreUnmapped((TypeMap map) => map.SourceType == src && map.DestinationType == dest); } public static void IgnoreUnmapped(this IProfileExpression profile) { profile.IgnoreUnmapped(typeof(TSrc), typeof(TDest)); } } 

Версия 5.0.0-beta-1 в AutoMapper вводит ForAllOtherMembers расширения ForAllOtherMembers поэтому теперь вы можете сделать это:

 CreateMap() .ForMember(d => d.Text, o => o.MapFrom(s => s.Name)) .ForMember(d => d.Value, o => o.MapFrom(s => s.Id)) .ForAllOtherMembers(opts => opts.Ignore()); 

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

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

Прошло несколько лет с тех пор, как был задан вопрос, но этот метод расширения кажется мне более чистым, используя текущую версию AutoMapper (3.2.1):

 public static IMappingExpression IgnoreUnmappedProperties(this IMappingExpression expression) { var typeMap = Mapper.FindTypeMapFor(); if (typeMap != null) { foreach (var unmappedPropertyName in typeMap.GetUnmappedPropertyNames()) { expression.ForMember(unmappedPropertyName, opt => opt.Ignore()); } } return expression; } 

Для тех, кто использует нестатический API в версии 4.2.0 и выше, можно использовать следующий метод расширения (найденный здесь в classе AutoMapperExtensions ):

 // from http://stackoverflow.com/questions/954480/automapper-ignore-the-rest/6474397#6474397 public static IMappingExpression IgnoreAllNonExisting(this IMappingExpression expression) { foreach(var property in expression.TypeMap.GetUnmappedPropertyNames()) { expression.ForMember(property, opt => opt.Ignore()); } return expression; } 

Важно то, что после удаления статического API код, такой как Mapper.FindTypeMapFor , больше не будет работать, следовательно, использование поля expression.TypeMap .

Для Automapper 5.0, чтобы пропустить все неподписанные свойства, вам просто нужно поставить

.ForAllOtherMembers (х => x.Ignore ());

в конце вашего профиля.

Например:

 internal class AccountInfoEntityToAccountDtoProfile : Profile { public AccountInfoEntityToAccountDtoProfile() { CreateMap() .ForMember(d => d.Id, e => e.MapFrom(s => s.BankAcctInfo.BankAcctFrom.AcctId)) .ForAllOtherMembers(x=>x.Ignore()); } } 

В этом случае будет разрешено только поле Id для выходного объекта, все остальные будут пропущены. Работает как шарм, кажется, нам больше не нужны какие-то сложные штучки!

Я обновил ответ Роберта Шредера для AutoMapper 4.2. При использовании нестатических конфигураций сопоставления мы не можем использовать Mapper.GetAllTypeMaps() , но expression имеет ссылку на требуемую TypeMap :

 public static IMappingExpression IgnoreAllNonExisting(this IMappingExpression expression) { foreach (var property in expression.TypeMap.GetUnmappedPropertyNames()) { expression.ForMember(property, opt => opt.Ignore()); } return expression; } 

Как бы вы предпочли указать, что некоторые члены игнорируются? Существует ли соглашение или базовый class или атрибут, который вы хотите применить? Как только вы входите в бизнес, указав все сопоставления явно, я не уверен, какое значение вы бы выбрали из AutoMapper.

Это кажется старым вопросом, но я думал, что отправлю свой ответ всем, кто был похож на меня.

Я использую ConstructUsing, инициализатор объекта в сочетании с ForAllMembers игнорируют, например

  Mapper.CreateMap() .ConstructUsing( f => new Target { PropVal1 = f.PropVal1, PropObj2 = Map(f.PropObj2), PropVal4 = f.PropVal4 }) .ForAllMembers(a => a.Ignore()); 

Единственная информация об игнорировании многих участников – это http://groups.google.com/group/automapper-users/browse_thread/thread/9928ce9f2ffa641f . Я думаю, вы можете использовать трюк, используемый в ProvidingCommonBaseClassConfiguration, чтобы игнорировать общие свойства для подобных classов.
И нет никакой информации об функциональности «Игнорировать остальных». Я уже смотрел код раньше, и мне кажется, что будет очень и очень сложно добавить такую ​​функциональность. Также вы можете попробовать использовать некоторый атрибут и пометить с ним игнорируемые свойства и добавить общий или общий код, чтобы игнорировать все отмеченные свойства.

Вы можете использовать ForAllMembers, чем переписывать только так, как это

 public static IMappingExpression IgnoreAll(this IMappingExpression expression) { expression.ForAllMembers(opt => opt.Ignore()); return expression; } 

Будьте осторожны, он игнорирует все, и если вы не добавите настраиваемое сопоставление, они уже игнорируют и не будут работать

также, я хочу сказать, если у вас есть модульный тест для AutoMapper. И вы проверяете, что все модели со всеми свойствами правильно сопоставлены, вы не должны использовать такой метод расширения

вы должны явно писать игнорировать

Я знаю, что это старый вопрос, но @jmoerdyk в вашем вопросе:

Как вы могли бы использовать это в выражении в цепочке CreateMap () в профиле?

вы можете использовать этот ответ так, как это внутри профиля ctor

 this.IgnoreUnmapped(); CreateMap(MemberList.Destination) .ForMember(dest => dest.SomeProp, opt => opt.MapFrom(src => src.OtherProp)); 

В версии 3.3.1 вы можете просто использовать IgnoreAllPropertiesWithAnInaccessibleSetter() или IgnoreAllSourcePropertiesWithAnInaccessibleSetter() .

Давайте будем гением компьютера.