有没有一种方法可以告诉AutoMapper忽略除了明确定义映射的属性以外的所有属性?
我有一些外部的DTO类,这些类可能会从外部发生变化,我想避免明确指定要忽略每个属性,因为添加新属性时,将尝试将它们映射到我的对象中会导致功能出现问题(引起异常)。
有没有一种方法可以告诉AutoMapper忽略除了明确定义映射的属性以外的所有属性?
我有一些外部的DTO类,这些类可能会从外部发生变化,我想避免明确指定要忽略每个属性,因为添加新属性时,将尝试将它们映射到我的对象中会导致功能出现问题(引起异常)。
据我所理解,问题是目标上有一些字段没有在源中进行映射,因此您正在寻找忽略这些未映射目标字段的方法。
您可以简单地使用而不是实现和使用这些扩展方法。
Mapper.CreateMap<sourceModel, destinationModel>(MemberList.Source);
现在自动映射知道它只需要验证所有源字段是否已映射,而不是反过来。
你也可以使用:
Mapper.CreateMap<sourceModel, destinationModel>(MemberList.Destination);
public static IMappingExpression<TSource, TDestination>
IgnoreAllNonExisting<TSource, TDestination>(this IMappingExpression<TSource, TDestination> expression)
{
var sourceType = typeof (TSource);
var destinationType = typeof (TDestination);
var existingMaps = Mapper.GetAllTypeMaps().First(x => x.SourceType.Equals(sourceType) && x.DestinationType.Equals(destinationType));
foreach (var property in existingMaps.GetUnmappedPropertyNames())
{
expression.ForMember(property, opt => opt.Ignore());
}
return expression;
}
用法:
Mapper.CreateMap<SourceType, DestinationType>()
.ForMember(prop => x.Property, opt => opt.MapFrom(src => src.OtherProperty))
.IgnoreAllNonExisting();
更新:请注意,在版本9.0中,映射器的静态API已被删除
Mapper.GetAllTypeMaps()
已被弃用) - mrmashalMapper.GetAllTypeMaps()
替换为Mapper.Configuration.GetAllTypeMaps()
即可。这是参考网址github.com/AutoMapper/AutoMapper/issues/1252。 - SerjGForAllOtherMembers
在Automapper 11中被移除了。
Automapper的5.0.0-beta-1版本引入了ForAllOtherMembers
扩展方法,使您现在可以执行以下操作:
CreateMap<Source, Destination>()
.ForMember(d => d.Text, o => o.MapFrom(s => s.Name))
.ForMember(d => d.Value, o => o.MapFrom(s => s.Id))
.ForAllOtherMembers(opts => opts.Ignore());
请注意,明确映射每个属性的好处是您永远不会遇到映射失败的问题,这种问题可能在您忘记映射属性时出现。
也许在您的情况下,忽略所有其他成员并添加TODO
以在此类更改频率稳定后回来进行明确映射可能是明智的选择。
ForAllOtherSourceMembers
这样的东西? - SuperJMNMemberList
的枚举类型,你只需要将它作为参数放入到CreateMap
方法中,就像这样:CreateMap<Source, Destination>(MemberList.Source)
。 - akim lyubchenko这是我编写的一个扩展方法,它会忽略目标对象上所有不存在的属性。不确定它是否仍然有用,因为这个问题已经过去两年了,但我遇到了同样的问题,需要添加许多手动的 Ignore 调用。
public static IMappingExpression<TSource, TDestination> IgnoreAllNonExisting<TSource, TDestination>
(this IMappingExpression<TSource, TDestination> expression)
{
var flags = BindingFlags.Public | BindingFlags.Instance;
var sourceType = typeof (TSource);
var destinationProperties = typeof (TDestination).GetProperties(flags);
foreach (var property in destinationProperties)
{
if (sourceType.GetProperty(property.Name, flags) == null)
{
expression.ForMember(property.Name, opt => opt.Ignore());
}
}
return expression;
}
使用方式:
Mapper.CreateMap<SourceType, DestinationType>()
.IgnoreAllNonExisting();
更新:显然,如果您有自定义映射,这种方法不起作用,因为它会覆盖自定义映射。我想,如果先调用IgnoreAllNonExisting,然后再调用自定义映射,则仍然可以使用该方法。
schdr提供了一种解决方案(作为此问题的答案),它使用Mapper.GetAllTypeMaps()
查找未映射的属性并自动忽略它们。对我来说,这似乎是一种更可靠的解决方案。
我能够通过以下方式实现这个:
Mapper.CreateMap<SourceType, DestinationType>().ForAllMembers(opt => opt.Ignore());
Mapper.CreateMap<SourceType, DestinationType>().ForMember(/*Do explicit mapping 1 here*/);
Mapper.CreateMap<SourceType, DestinationType>().ForMember(/*Do explicit mapping 2 here*/);
...
注意:我正在使用AutoMapper v.2.0。
从AutoMapper 5.0开始,IMappingExpression
上的 .TypeMap
属性已被删除,这意味着4.2版本的解决方案不再可用。我创建了一个解决方案,它使用原始功能但具有不同的语法:
var config = new MapperConfiguration(cfg =>
{
cfg.CreateMap<Src, Dest>();
cfg.IgnoreUnmapped(); // Ignores unmapped properties on all maps
cfg.IgnoreUnmapped<Src, Dest>(); // Ignores unmapped properties on specific map
});
// or add inside a profile
public class MyProfile : Profile
{
this.IgnoreUnmapped();
CreateMap<MyType1, MyType2>();
}
实现:
public static class MapperExtensions
{
private static void IgnoreUnmappedProperties(TypeMap map, IMappingExpression expr)
{
foreach (string propName in map.GetUnmappedPropertyNames())
{
if (map.SourceType.GetProperty(propName) != null)
{
expr.ForSourceMember(propName, opt => opt.Ignore());
}
if (map.DestinationType.GetProperty(propName) != null)
{
expr.ForMember(propName, opt => opt.Ignore());
}
}
}
public static void IgnoreUnmapped(this IProfileExpression profile)
{
profile.ForAllMaps(IgnoreUnmappedProperties);
}
public static void IgnoreUnmapped(this IProfileExpression profile, Func<TypeMap, bool> filter)
{
profile.ForAllMaps((map, expr) =>
{
if (filter(map))
{
IgnoreUnmappedProperties(map, expr);
}
});
}
public static void IgnoreUnmapped(this IProfileExpression profile, Type src, Type dest)
{
profile.IgnoreUnmapped((TypeMap map) => map.SourceType == src && map.DestinationType == dest);
}
public static void IgnoreUnmapped<TSrc, TDest>(this IProfileExpression profile)
{
profile.IgnoreUnmapped(typeof(TSrc), typeof(TDest));
}
}
Profile
中的链式 CreateMap<TSource,TDest>()
表达式中使用它? - jmoerdyk如果您想跳过所有未映射的属性,请在您的配置文件末尾加上
.ForAllOtherMembers(x=>x.Ignore());
例如:
internal class AccountInfoEntityToAccountDtoProfile : Profile
{
public AccountInfoEntityToAccountDtoProfile()
{
CreateMap<AccountInfoEntity, AccountDto>()
.ForMember(d => d.Id, e => e.MapFrom(s => s.BankAcctInfo.BankAcctFrom.AcctId))
.ForAllOtherMembers(x=>x.Ignore());
}
}
在这种情况下,只有输出对象的 Id 字段会被解析,其他所有字段都将被跳过。起作用就像魔法一样,似乎我们不再需要任何棘手的扩展了!
这个问题已经问了几年了,但是对我来说,使用当前版本的AutoMapper(3.2.1),这个扩展方法似乎更加简洁:
public static IMappingExpression<TSource, TDestination> IgnoreUnmappedProperties<TSource, TDestination>(this IMappingExpression<TSource, TDestination> expression)
{
var typeMap = Mapper.FindTypeMapFor<TSource, TDestination>();
if (typeMap != null)
{
foreach (var unmappedPropertyName in typeMap.GetUnmappedPropertyNames())
{
expression.ForMember(unmappedPropertyName, opt => opt.Ignore());
}
}
return expression;
}
对于那些使用版本4.2.0及以上的非静态API的人,可以使用以下扩展方法(在AutoMapperExtensions
类中找到此处):
// from https://dev59.com/3nNA5IYBdhLWcg3wdthd#6474397
public static IMappingExpression IgnoreAllNonExisting(this IMappingExpression expression)
{
foreach(var property in expression.TypeMap.GetUnmappedPropertyNames())
{
expression.ForMember(property, opt => opt.Ignore());
}
return expression;
}
Mapper.FindTypeMapFor
这样的代码将不再起作用,因此需要使用expression.TypeMap
字段。public static IMappingExpression<TSource, TDestination> IgnoreAllNonExisting<TSource, TDestination>(this IMappingExpression<TSource, TDestination> expression)
来解决类型问题。 - Nick M我已更新Robert Schroeder的AutoMapper 4.2答案。 对于非静态映射配置,我们不能使用Mapper.GetAllTypeMaps()
,但是expression
引用了所需的TypeMap
:
public static IMappingExpression<TSource, TDestination>
IgnoreAllNonExisting<TSource, TDestination>(this IMappingExpression<TSource, TDestination> expression)
{
foreach (var property in expression.TypeMap.GetUnmappedPropertyNames())
{
expression.ForMember(property, opt => opt.Ignore());
}
return expression;
}
.ForAllOtherMembers(opts => opts.Ignore())
的答案。 - Jack Ukleja