AutoMapper: “Ignorar el rest”?

¿Hay alguna manera de decirle a AutoMapper que ignore todas las propiedades, excepto las que están mapeadas explícitamente?

Tengo clases externas de DTO que es probable que cambien desde el exterior y deseo evitar especificar que cada propiedad se ignore explícitamente, ya que agregar nuevas propiedades romperá la funcionalidad (causar excepciones) cuando intente mapearlas en mis propios objetos.

Este es un método de extensión que escribí que ignora todas las propiedades no existentes en el destino. No estoy seguro si todavía será útil ya que la pregunta tiene más de dos años, pero me encontré con el mismo problema al tener que agregar muchas llamadas Ignorar manualmente.

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

Uso:

 Mapper.CreateMap() .IgnoreAllNonExisting(); 

ACTUALIZACIÓN : Aparentemente, esto no funciona correctamente si tiene asignaciones personalizadas porque las sobrescribe. Supongo que aún podría funcionar si llama primero a IgnoreAllNonExisting y luego a las asignaciones personalizadas más tarde.

schdr tiene una solución (como respuesta a esta pregunta) que utiliza Mapper.GetAllTypeMaps() para descubrir qué propiedades no están mapeadas y las ignora automáticamente. Parece una solución más robusta para mí.

Actualicé la extensión de Can Gencer para no sobrescribir ningún mapa existente.

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

Uso:

 Mapper.CreateMap() .ForMember(prop => x.Property, opt => opt.MapFrom(src => src.OtherProperty)) .IgnoreAllNonExisting(); 

Por lo que entendí, la pregunta era que hay campos en el destino que no tienen un campo mapeado en la fuente, razón por la cual está buscando formas de ignorar esos campos de destino no mapeados.

En lugar de implementar y usar estos métodos de extensión, simplemente podría usar

 Mapper.CreateMap(MemberList.Source); 

Ahora el automapper sabe que solo necesita validar que todos los campos de origen estén mapeados, pero no al revés.

Pude hacer esto de la siguiente manera:

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

Nota: Estoy usando AutoMapper v.2.0.

A partir de AutoMapper 5.0, la propiedad .TypeMap en IMappingExpression se ha ido, lo que significa que la solución 4.2 ya no funciona. Creé una solución que usa la funcionalidad original pero con una syntax diferente:

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

Implementación:

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

La versión 5.0.0-beta-1 de AutoMapper presenta el método de extensión ForAllOtherMembers para que pueda hacer lo siguiente:

 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()); 

Tenga en cuenta que existe una ventaja al mapear explícitamente cada propiedad, ya que nunca tendrá problemas de fallas en el mapeo que surgen cuando se olvida de mapear una propiedad.

Tal vez en su caso sea sabio ignorar a todos los demás miembros y agregar un TODO para volver y hacer que estos sean explícitos una vez que se establezca la frecuencia de los cambios en esta clase.

Han pasado algunos años desde que se formuló la pregunta, pero este método de extensión me parece más limpio, utilizando la versión actual de 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; } 

Para aquellos que están usando la API no estática en la versión 4.2.0 y superior, se puede utilizar el siguiente método de extensión (que se encuentra aquí en la clase 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; } 

Lo importante aquí es que una vez que se elimina la API estática, el código como Mapper.FindTypeMapFor ya no funcionará, de ahí el uso del campo expression.TypeMap .

Para Automapper 5.0 con el fin de omitir todas las propiedades no asignadas solo necesita poner

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

al final de tu perfil

Por ejemplo:

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

En este caso, solo se resolverá el campo Id para el objeto de salida, todos los demás serán omitidos. Funciona como un encanto, parece que ya no necesitamos extensiones complicadas.

He actualizado la respuesta de Robert Schroeder para AutoMapper 4.2. Con configuraciones de mapper no estáticas, no podemos usar Mapper.GetAllTypeMaps() , pero la expression tiene una referencia al TypeMap requerido:

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

¿Cómo preferiría especificar que ciertos miembros sean ignorados? ¿Existe una convención, clase base o atributo que le gustaría aplicar? Una vez que se dedica a la tarea de especificar todas las asignaciones explícitamente, no estoy seguro de qué valor obtendría de AutoMapper.

Parece una vieja pregunta, pero pensé que publicaría mi respuesta para cualquiera que se pareciera a mí.

Yo uso ConstructUsing, el inicializador de objetos junto con ForAllMembers ignoran, por ejemplo

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

La única información sobre ignorar a muchos miembros es este hilo: http://groups.google.com/group/automapper-users/browse_thread/thread/9928ce9f2ffa641f . Creo que puedes usar el truco utilizado en ProvidingCommonBaseClassConfiguration para ignorar propiedades comunes para clases similares.
Y no hay información sobre la funcionalidad “Ignorar el rest”. Miré el código antes y me parece que será muy difícil agregar dicha funcionalidad. También puede intentar usar algún atributo y marcar con él las propiedades ignoradas y agregar algún código genérico / común para ignorar todas las propiedades marcadas.

Puede usar ForAllMembers, que sobreescribir solo necesario como este

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

Tenga cuidado, ignorará todo, y si no va a agregar una asignación personalizada, ya están ignorados y no funcionarán

también, quiero decir, si tienes una unidad de prueba para AutoMapper. Y prueba que todos los modelos con todas las propiedades mapeadas correctamente no deberían usar dicho método de extensión

deberías escribir ignorar explícitamente

Sé que esta es una vieja pregunta, pero @jmoerdyk en su pregunta:

¿Cómo usarías esto en una expresión de CreateMap () encadenada en un perfil?

puede usar esta respuesta de esta manera dentro del Perfil ctor

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

En la versión de 3.3.1, simplemente puede usar los IgnoreAllPropertiesWithAnInaccessibleSetter() o IgnoreAllSourcePropertiesWithAnInaccessibleSetter() .