有没有一种方法告诉AutoMapper忽略所有的属性,除了那些显式映射的?
我有可能从外部更改的外部DTO类,并且我希望避免显式地指定要忽略的每个属性,因为添加新属性将在尝试将它们映射到自己的对象时破坏功能(导致异常)。
有没有一种方法告诉AutoMapper忽略所有的属性,除了那些显式映射的?
我有可能从外部更改的外部DTO类,并且我希望避免显式地指定要忽略的每个属性,因为添加新属性将在尝试将它们映射到自己的对象时破坏功能(导致异常)。
当前回答
从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));
}
}
其他回答
这是我编写的一个扩展方法,它忽略目标上所有不存在的属性。不确定它是否仍然有用,因为这个问题已经存在两年多了,但我遇到了同样的问题,必须添加大量手动忽略调用。
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有一个解决方案(作为这个问题的答案),它使用map . getalltypemaps()来找出哪些属性未映射并自动忽略它们。在我看来这是个更可靠的解决方案。
更新:这个答案对那些使用最新版本的Automapper不再有用,因为ForAllOtherMembers已经在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来返回,并在该类的更改频率稳定下来后显式地显示这些成员。
我已经更新了Can Gencer的扩展,不覆盖任何现有的地图。
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版本Mapper静态API被删除
默认情况下,AutoMapper使用目标类型来验证成员,但您可以通过使用MemberList跳过验证。没有选择。
var configuration = new MapperConfiguration(cfg =>
cfg.CreateMap<Source2, Destination2>(MemberList.None);
);
你可以在这里找到参考资料
在dotnet 5的WebApi中,使用Nuget包automapper . extensions .微软。DependencyInjection,我在一个映射器配置文件中这样做。我对AutoMapper真的生疏了,但它现在似乎对未映射的成员工作得很好。
在启动:
var mapperConfig = new MapperConfiguration(mc => mc.AddProfile(new AutoMapperProfile()));
services.AddSingleton(mapperConfig.CreateMapper());
在我的AutoMapperProfile中:
CreateMap<ProjectActivity, Activity>()
.ForMember(dest => dest.ActivityName, opt => opt.MapFrom(src => src.Name))
.ValidateMemberList(MemberList.None);