Ignorar la asignación de una propiedad con Automapper


285

Estoy usando Automapper y tengo el siguiente escenario: Class OrderModel tiene una propiedad llamada 'ProductName' que no está en la base de datos. Entonces, cuando trato de hacer el mapeo con:

Mapper.CreateMap<OrderModel, Orders>(); 

Genera una excepción:

"Las siguientes 1 propiedades en Project.ViewModels.OrderModel no están asignadas: 'ProductName'

Leí en el Wiki de AutoMapper para proyecciones el caso opuesto (el atributo adicional está en el destino, no en la fuente, que en realidad es mi caso)

¿Cómo puedo evitar que automapper haga el mapeo de esta propiedad?


77
Automapper no funciona de esa manera. Solo le preocupan las propiedades en el objeto de destino. El src puede contener 100 propiedades adicionales: Automapper solo asigna las propiedades de destino. Debe haber algo más que cause la excepción de mapeo. ¿Puedes publicar algún código de lo que no funciona?
PatrickSteele

Hace lo que pides automáticamente. Publique un código para aclarar
BeRecursive

Eche un vistazo a las siguientes publicaciones, estas pueden ayudarlo a stackoverflow.com/questions/4456519/… stackoverflow.com/questions/4052579/…
Divi

3
@Patrick AutoMapper hace algunos trucos para analizar nombres de métodos / propiedades. Es posible que haya una propiedad en la fuente que se esté mapeando involuntariamente, incluso si no hay una coincidencia exacta en el destino. Es por eso que hay un ForSourceMember (... Ignore ()) para evitar esto cuando ocurre.
AaronLS

Respuestas:


477

De Jimmy Bogard: CreateMap<Foo, Bar>().ForMember(x => x.Blarg, opt => opt.Ignore());

Está en uno de los comentarios en su blog .


13
Además, CreateMap<Foo, Bar>().ForSourceMember(x => x.Blarg, opt => opt.Ignore());podría ser útil
stackoverfloweth

55
@stackoverfloweth ¿No quieres decir CreateMap<SourceType, DestType> (MemberList.Source).ForSourceMember(x => x.MySourceProperty, opt => opt.DoNotValidate()):?
Monty

12
Ignorar ha sido reemplazado con DoNotValidate en ForSourceMember: github.com/AutoMapper/AutoMapper/blob/master/docs/…
Jamie

@Jamie @monty: comencé a actualizar este re: su comentario, pero parece que el cambio de sintaxis solo afecta el caso de proyección (donde la propiedad de origen debe ignorarse). La solicitud del OP es ignorar una propiedad de destino, por lo tanto, Ignore()sigue siendo la sintaxis correcta. Esto se debe a que el cambio de sintaxis Ignorese realizó en la ISourceMemberConfigurationExpressioninterfaz pero no en la IMemberConfigurationExpression`3interfaz disjunta .
smartcaveman

2
@Franva ForMember () es en realidad "ForDestinationMember ()"
rvnlord

243

Tal vez soy un poco perfeccionista; Realmente no me gusta la sintaxis ForMember (..., x => x.Ignore ()). Es una pequeña cosa, pero me importa. Escribí este método de extensión para hacerlo un poco más agradable:

public static IMappingExpression<TSource, TDestination> Ignore<TSource, TDestination>(
    this IMappingExpression<TSource, TDestination> map,
    Expression<Func<TDestination, object>> selector)
{
    map.ForMember(selector, config => config.Ignore());
    return map;
}

Se puede usar así:

Mapper.CreateMap<JsonRecord, DatabaseRecord>()
        .Ignore(record => record.Field)
        .Ignore(record => record.AnotherField)
        .Ignore(record => record.Etc);

También podría reescribirlo para trabajar params, pero no me gusta la apariencia de un método con muchas lambdas.


66
Sé que esto va más allá de la pregunta inicial, pero realmente me gusta esta respuesta, es limpia, muy fácil de leer y comprender al instante, además de fácil de reutilizar
Lski

En cuanto a params: podría devolver una serie de selectores desde el interior de una sola lambda, luego asignar sobre cada selector con foreacho Select()tal vez no menos desordenado.
jpaugh

gracias @Steve Rukuts, para cualquier persona que esté buscando un método de extensión para ignorar a los miembros fuente, puede usar esta IMappingExpression estática pública <TSource, TDestination> IgnoreSourceValidation <TSource, TDestination> (este IMappingExpression <TSource, TDestination> mapa, Expression <Func <TSource , objeto >> selector) {map.ForSourceMember (selector, config => config.DoNotValidate ()); mapa de retorno; }
Jason Dias

79

Puedes hacerlo:

conf.CreateMap<SourceType, DestinationType>()
   .ForSourceMember(x => x.SourceProperty, y => y.Ignore());

¿Automapper tiene una extensión ForSourceMember?
Canjeado1

Hago esto actualmente, pero sería ideal NO tener que crear todos estos Ignorar ...: /
Tom Stickel

¿Sabes si hay una manera de ignorar cuando realmente haces el mapeo y no cuando creas el mapa?
Soy Sam, dice Restablecer a Mónica el


3
Para el escenario dado en la pregunta, esta debería ser la respuesta aceptada. La respuesta aceptada actual ignora la asignación de propiedades en el objeto de destino. Esta pregunta es sobre ignorar las asignaciones en el objeto fuente.
Rob S.

28

Solo para cualquiera que intente hacer esto automáticamente, puede usar ese método de extensión para ignorar las propiedades no existentes en el tipo de destino:

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

Para ser utilizado de la siguiente manera:

Mapper.CreateMap<SourceType, DestinationType>().IgnoreAllNonExisting();

gracias a Can Gencer por el consejo :)

fuente: http://cangencer.wordpress.com/2011/06/08/auto-ignore-non-existing-properties-with-automapper/



1
Esto no funciona al inyectar IMapper. Mapper.GetAllTypeMaps no existe en la última versión de AutoMapper. Además, cuando configuré mis mapas en un AutoMapper.Profile y luego inyecté IMapper posteriormente, recibí esta excepción "Mapper no inicializado. Llame a Initialize con la configuración adecuada. Si está tratando de usar instancias de mapper a través de un contenedor o no, asegúrese de que no tiene ninguna llamada a los métodos estáticos Mapper.Map, y si está utilizando los métodos de extensión ProjectTo o UseAsDataSource, asegúrese de pasar la instancia apropiada de IConfigurationProvider ".
Ristogod

Acabo de llegar 'Mapper' does not contain a definition for 'GetAllTypeMaps' [DSSTools]..
Bassie

2
@Bassie Use Mapper.Configuration.GetAllTypeMaps() source
Mike Bovenlander

28

Ahora hay (AutoMapper 2.0) un IgnoreMapatributo, que voy a usar en lugar de la sintaxis fluida, que es un poco pesado en mi humilde opinión.


35
Sin embargo, el atributo ignorar filtra automáticamente el mapeador a través de su aplicación.
Phill

11
AutoMapper es una cosa que no me importa filtrar por todas partes. ;)
Pawel Krakowiak

44
Siempre puedes considerar derivar IgnoreMapAttribute.
Alapago

1
Esta es una buena manera de ignorar una propiedad base que se hereda en muchos objetos. Evita tener que ignorarlo en cada configuración de mapeo.
Chase Florell

23

Al asignar un modelo de vista de nuevo a un modelo de dominio, puede ser mucho más limpio simplemente validar la lista de miembros de origen en lugar de la lista de miembros de destino

Mapper.CreateMap<OrderModel, Orders>(MemberList.Source); 

Ahora mi validación de mapeo no falla, requiriendo otra Ignore(), cada vez que agrego una propiedad a mi clase de dominio.


77
ESTO es lo que vine buscando, tan útil cuando solo se modifica un subconjunto de propiedades de objeto de dominio desde un DTO mucho más simple.
Adam Tolley

55
Esta es la respuesta, niños, hagan eso oficial para que los novatos no se confundan
Piotr M

0

Podría usar IgnoreAttribute en la propiedad que debe ignorarse


2
Es [IgnoreMap]deIgnoreMapAttribute
fiorebat

-5

Hola a todos Por favor, use esto, está funcionando bien ... para el mapeador automático use múltiples .ForMember en C #

        if (promotionCode.Any())
        {
            Mapper.Reset();
            Mapper.CreateMap<PromotionCode, PromotionCodeEntity>().ForMember(d => d.serverTime, o => o.MapFrom(s => s.promotionCodeId == null ? "date" : String.Format("{0:dd/MM/yyyy h:mm:ss tt}", DateTime.UtcNow.AddHours(7.0))))
                .ForMember(d => d.day, p => p.MapFrom(s => s.code != "" ? LeftTime(Convert.ToInt32(s.quantity), Convert.ToString(s.expiryDate), Convert.ToString(DateTime.UtcNow.AddHours(7.0))) : "Day"))
                .ForMember(d => d.subCategoryname, o => o.MapFrom(s => s.subCategoryId == 0 ? "" : Convert.ToString(subCategory.Where(z => z.subCategoryId.Equals(s.subCategoryId)).FirstOrDefault().subCategoryName)))
                .ForMember(d => d.optionalCategoryName, o => o.MapFrom(s => s.optCategoryId == 0 ? "" : Convert.ToString(optionalCategory.Where(z => z.optCategoryId.Equals(s.optCategoryId)).FirstOrDefault().optCategoryName)))
                .ForMember(d => d.logoImg, o => o.MapFrom(s => s.vendorId == 0 ? "" : Convert.ToString(vendorImg.Where(z => z.vendorId.Equals(s.vendorId)).FirstOrDefault().logoImg)))
                .ForMember(d => d.expiryDate, o => o.MapFrom(s => s.expiryDate == null ? "" : String.Format("{0:dd/MM/yyyy h:mm:ss tt}", s.expiryDate))); 
            var userPromotionModel = Mapper.Map<List<PromotionCode>, List<PromotionCodeEntity>>(promotionCode);
            return userPromotionModel;
        }
        return null;
Al usar nuestro sitio, usted reconoce que ha leído y comprende nuestra Política de Cookies y Política de Privacidad.
Licensed under cc by-sa 3.0 with attribution required.