我想使用automapper在我的公共数据协定和我的数据库模型之间进行映射.我创建了一个自动完成所有契约的类创建映射.我唯一的问题是,如果值不为null,我只想将合约中的值映射到数据库模型.我在这里看了其他问题但是看不到使用自定义解析器的示例.
这是我的一些代码
var mapToTarget = AutoMapper.Mapper.CreateMap(contract, mappedTo);
foreach (var property in contract.GetProperties().Where(property => property.CustomAttributes.Any(a => a.AttributeType == typeof(MapsToProperty))))
{
var attribute = property.GetCustomAttributes(typeof(MapsToProperty), true).FirstOrDefault() as MapsToProperty;
if (attribute == null) continue;
mapToTarget.ForMember(attribute.MappedToName,
opt =>
opt.ResolveUsing<ContractToSourceResolver>()
.ConstructedBy(() => new ContractToSourceResolver(new MapsToProperty(property.Name, attribute.SourceToContractMethod, attribute.ContractToSourceMethod))));
}
private class ContractToSourceResolver : ValueResolver<IDataContract, object>
{
private MapsToProperty Property { get; set; }
public ContractToSourceResolver(MapsToProperty property)
{
Property = property;
}
protected override object ResolveCore(IDataContract contract)
{
object result = null;
if (Property.ContractToSourceMethod != null)
{
var method = contract.GetType()
.GetMethod(Property.ContractToSourceMethod, BindingFlags.Public | BindingFlags.Static);
result = method != null ? method.Invoke(null, new object[] {contract}) : null;
}
else
{
var property =
contract.GetType().GetProperties().FirstOrDefault(p => p.Name == Property.MappedToName);
if (property != null)
{
result = property.GetValue(contract);
}
}
return result;
}
}
Run Code Online (Sandbox Code Playgroud)
这就是我想要使用它的方式
AutoMapper.Mapper.Map(dataContract, dbModel)
Run Code Online (Sandbox Code Playgroud)
这当前工作得很好但是如果dataContract中有一个NULL值,那么它将替换dbModel中的现有值,这不是我想要的.如何使AutoMapper忽略空源值?
编辑
正如其中一个答案所指出的那样
Mapper.CreateMap<SourceType, DestinationType>().ForAllMembers(opt => opt.Condition(srs => !srs.IsSourceValueNull));
Run Code Online (Sandbox Code Playgroud)
这是理想的,除了.ForAllMembers无法访问的事实
Mapper.CreateMap(SourceType, DestinationType)
Run Code Online (Sandbox Code Playgroud)
Pra*_*thi 30
更新:从V5开始, IsSourceValueNull 不可用.
如果希望忽略具有空值的所有源属性,则可以使用:
Mapper.CreateMap<SourceType, DestinationType>()
.ForAllMembers(opt => opt.Condition(srs => !srs.IsSourceValueNull));
Run Code Online (Sandbox Code Playgroud)
否则,您可以为每个成员执行类似的操作.
读这个.
Mar*_*pez 15
对于使用Instance API的较新版本,请改用:
var mappingConfig = new MapperConfiguration(cfg =>
{
cfg.CreateMap<SourceType, DestinationType>().ForAllMembers(opt => opt.Condition(
(source, destination, sourceMember, destMember) => (sourceMember != null)));
});
Run Code Online (Sandbox Code Playgroud)
注意:此功能从5.0.2开始工作,在撰写本文时打破了更高版本.如果从5.0.2升级,建议等待下一个5.2.x版本.
该解决方案在这里工作我的项目,这是使用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)