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

Sik*_*kor 28 c# mapping automapper

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

我的映射:

CreateMap<StatusLevelDTO, StatusLevel>()
            .ForAllMembers(opt => opt.Condition(src => src != null));
Run Code Online (Sandbox Code Playgroud)

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

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

我已经看到了这个问题:Automapper使用自定义解析器跳过空值并尝试了前两个答案,但它们似乎都已过时版本6.

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

Ser*_*kiy 48

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

Func<TSource, TDestination, TMember, bool>
Run Code Online (Sandbox Code Playgroud)

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

CreateMap<StatusLevelDTO, StatusLevel>()
     .ForAllMembers(opts => opts.Condition((src, dest, srcMember) => srcMember != null));
Run Code Online (Sandbox Code Playgroud)

  • 实际上,在发布此问题之前,我已经尝试过类似的操作。唯一的区别是,我使用了4个参数,例如:( src,dest,srcMember,dstMember),但没有用。我再次检查了您的版本,但仍然无法正常工作。 (2认同)
  • @Sikor 似乎源对象中有“int?”,目标中有“int”。当 AutoMapper 尝试映射此字段时,它会检查目标是否可为空并使用默认 int 值作为 sourceMember 值。这就是为什么空检查条件失败并且此默认值被分配给目标对象的原因 (2认同)

Che*_*som 34

这可能已经晚了,但对于那些仍在寻找的人来说,这可能会像我一样解决您的问题。

我同意@sergey 使用:

CreateMap<StatusLevelDTO, StatusLevel>()
    .ForAllMembers(opts => opts.Condition((src, dest, srcMember) => srcMember != null));
Run Code Online (Sandbox Code Playgroud)

但是将可为空映射到不可为空会是一个像 int 一样的问题吗?转换为 int 时,它总是返回 0。要修复它,您可以转换 int 吗?映射中的 int。

CreateMap<int?, int>().ConvertUsing((src, dest) => src ?? dest);
CreateMap<StatusLevelDTO, StatusLevel>()
     .ForAllMembers(opts => opts.Condition((src, dest, srcMember) => srcMember != null));
Run Code Online (Sandbox Code Playgroud)

  • 在尝试了这么多选项之后,我陷入了我的 Nullable `DateTime` 仍然被映射到 DateTime.MinValue (0001-01-01) 的位置,并且当它的值为 null 时我无法排除该属性。就像您对“int”所做的那样,将“DateTime?”映射到“DateTime”对我有用。 (3认同)
  • 完美的。谢谢! (2认同)
  • 救生员 (2认同)

Far*_*nov 8

我受到@Sergey Berezovskiy的回答的启发,并在主配置中为所有地图的所有成员进行了此配置:

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


Tim*_*Tim 7

该解决方案在这里工作我的项目,这是使用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;
    }
}
Run Code Online (Sandbox Code Playgroud)

  • 需要在 *AutoMapper 8.1.1* 中使用一些更改: *cfg.ForAllPropertyMaps(pm =&gt; pm.TypeMap.SourceType == typeof(&lt;class of source object&gt;), (pm, c) =&gt; c.MapFrom(new IgnoreNullResolver(), pm.SourceMember.Name))* (3认同)