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?

Msam85
fuente
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 .

Smartcaveman
fuente
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.

Steve Rukuts
fuente
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());
Ricardo
fuente
¿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
FYI: se fusionó de stackoverflow.com/questions/4052579/…
Shog9
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/

Stéphane
fuente
3
FYI: se fusionó de stackoverflow.com/questions/4052579/…
Shog9
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.

Guillaume
fuente
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.

Loren Paulsen
fuente
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

Naresh
fuente
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;
ravikant sonare
fuente