如何在Automapper 6中映射期间忽略所有源成员的空值?

问题描述 投票:24回答:4

我一直在寻找各处:stackoverflow,automapper文档,互联网,只是找不到任何关于这个的信息,即使这似乎是一个非常普遍的问题。

我的映射:

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

这不起作用,因为src表示源对象(StatusLevelDTO),而不是源属性(我认为)。

更具体地说,如果我将ObjectA映射到Object,ObjectS.Some Value为null并且ObjectB.SomeValue为2,我希望目标对象保持其值(2)。

我已经看到了这个问题:Automapper skip null values with custom resolver并尝试了前两个答案,但它们似乎都已经过时了。

有没有办法在Automapper 6中实现这一点?我准确地使用6.0.2。

c# mapping automapper
4个回答
40
投票

方法Condition现在有五个重载,其中一个接受类型的谓词

Func<TSource, TDestination, TMember, bool>

此TMember参数是源成员。因此,您可以检查源成员是否为null:

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

5
投票

解决方案here适用于我的项目,该项目使用的是AutoMapper 6.0.2。在以前使用AutoMapper 4的项目中,我使用了IsSourceValueNull来实现相同的行为。

我对原始解决方案做了一些小改动。我没有检查要映射的属性的类型,而是在ForAllPropertyMaps中设置过滤器以检查源对象的类型,以便自定义解析器仅应用于该源对象的映射。但是过滤器可以根据需要设置为任何东西。

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

0
投票

我从@Sergey Berezovskiy的答案中获得灵感,并为主配置中所有地图的所有成员进行了此配置:

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

0
投票

由于我没有评论的声誉,我将在这里为@Sikor @sensei添加我的答案

如果您使用的模型具有DTO的可空数据类型,则可以使用下面的此扩展方法来消除Automapper对特定数据类型的默认值的影响。

模型示例

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

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

扩展方法:

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

用法

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

这会将Dto属性值映射到所有模型的null属性值。然后将模型属性值映射回Dto,从而仅更改模型中存在的Dto值。

© www.soinside.com 2019 - 2024. All rights reserved.