net c# mapping automapper

c# - net - ¿Cómo ignorar los valores nulos para todos los miembros fuente durante la asignación en Automapper 6?



automapper nuget (4)

He estado buscando en todas partes: stackoverflow, documentación de automapper, Internet y simplemente no pude encontrar ninguna información sobre este, incluso aunque esto parece ser un problema muy común.

Mi mapeo:

CreateMap<StatusLevelDTO, StatusLevel>() .ForAllMembers(opt => opt.Condition(src => src != null));

Esto no funciona porque src representa el objeto fuente (StatusLevelDTO), no una propiedad fuente (creo).

Para ser más específico, si asigno ObjectA a ObjectB, ObjectA.SomeValue es nulo y ObjectB.SomeValue es 2, quiero que el objeto de destino mantenga su valor (2).

He visto esta pregunta: Automapper omite valores nulos con resolución personalizada y probé las dos primeras respuestas, pero ambas parecen estar desactualizadas para la versión 6.

¿Hay alguna manera de hacer que esto suceda en Automapper 6? Estoy usando 6.0.2 para ser exactos.


Como no tengo la reputación de comentar, agregaré mi respuesta aquí para @Sikor @sensei

Si está utilizando un modelo que tiene los tipos de datos anulables de su DTO, puede usar este método de extensión a continuación para negar los efectos de que Automapper recurra al valor predeterminado del tipo de datos en particular.

Ejemplos de modelos

public class Foo { public bool? Example { get; set; } } public class FooDto { public bool Example { get; set; } }

Método de extensión:

public static TTarget MapModelProperties<TTarget, TSource>(this TTarget target, TSource source) where TTarget : class where TSource : class { // Map target into the source, where the source property is null Mapper.Initialize(cfg => { cfg.CreateMap<TTarget, TSource>() .ForAllMembers(opt => opt.Condition((src, dest, srcMember, destMember) => destMember == null)); }); Mapper.Map(target, source); // Map the source into the target to apply the changes Mapper.Initialize(cfg => cfg.CreateMap<TSource, TTarget>()); Mapper.Map(source, target); return target; }

Uso

public class Foo { public bool? Example { get; set; } } public class FooDto { public bool Example { get; set; } } public void Example() { var foo = new Foo { Example = null }; var fooDto = new FooDto { Example = true }; fooDto.MapModelProperties(foo); }

Esto asigna los valores de propiedad Dto en todos los valores de propiedad del modelo que son nulos. Luego asigna los valores de propiedad del modelo de nuevo al Dto, por lo que solo cambia los valores de Dto que están presentes en el modelo.


La Condition método ahora tiene cinco sobrecargas, una de las cuales acepta predicado de tipo

Func<TSource, TDestination, TMember, bool>

Este parámetro TMember es el miembro fuente. Para que pueda verificar el miembro de origen para nulo:

CreateMap<StatusLevelDTO, StatusLevel>() .ForAllMembers(opts => opts.Condition((src, dest, srcMember) => srcMember != null));


La solución here funciona para mi proyecto, que usa AutoMapper 6.0.2. En proyectos anteriores que usaban AutoMapper 4, había usado IsSourceValueNull para lograr el mismo comportamiento.

Hice un pequeño cambio en la solución original. En lugar de verificar el tipo de propiedad que se va a asignar, configuro el filtro en ForAllPropertyMaps para verificar el tipo del objeto de origen, de modo que la resolución personalizada solo se aplique a los mapas de ese objeto de origen. Pero el filtro se puede establecer en cualquier cosa según sea necesario.

var config = new MapperConfiguration(cfg => { cfg.ForAllPropertyMaps( pm => pm.TypeMap.SourceType == typeof(<class of source object>), (pm, c) => c.ResolveUsing<object, object, object, object>(new IgnoreNullResolver(), pm.SourceMember.Name)); }); class IgnoreNullResolver : IMemberValueResolver<object, object, object, object> { public object Resolve(object source, object destination, object sourceMember, object destinationMember, ResolutionContext context) { return sourceMember ?? destinationMember; } }


Me inspiré en la @Sergey Berezovskiy de @Sergey Berezovskiy e hice esta configuración para todos los miembros de todos los mapas en la configuración principal:

Mapper.Initialize(cfg => { cfg.ForAllMaps((obj, cnfg) => cnfg.ForAllMembers(opts => opts.Condition((src, dest, srcMember) => srcMember != null))); }