我一直在寻找各处: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。
方法Condition
现在有五个重载,其中一个接受类型的谓词
Func<TSource, TDestination, TMember, bool>
此TMember参数是源成员。因此,您可以检查源成员是否为null:
CreateMap<StatusLevelDTO, StatusLevel>()
.ForAllMembers(opts => opts.Condition((src, dest, srcMember) => srcMember != null));
解决方案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;
}
}
我从@Sergey Berezovskiy
的答案中获得灵感,并为主配置中所有地图的所有成员进行了此配置:
Mapper.Initialize(cfg =>
{
cfg.ForAllMaps((obj, cnfg) => cnfg.ForAllMembers(opts => opts.Condition((src, dest, srcMember) => srcMember != null)));
}
由于我没有评论的声誉,我将在这里为@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值。