AutoMapper:“忽略其余”?

有没有办法告诉AutoMapper忽略除了显式映射的属性之外的所有属性?

我有外部DTO类,可能会从外面改变,我想避免指定每个属性被明确忽略,因为添加新的属性将打破function(导致exception),当试图映射到我自己的对象。

这是我写的一个扩展方法,忽略了目标上的所有不存在的属性。 不知道它是否仍然有用,因为这个问题已经两年多了,但是我遇到了同样的问题,不得不添加大量的手动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有一个解决scheme(作为这个问题的答案),它使用Mapper.GetAllTypeMaps()来找出哪些属性未映射,并自动忽略它们。 看起来像一个更强大的解决scheme给我。

我已经更新了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(); 

我已经能够以下面的方式做到这一点:

 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。

从我所理解的问题是,有目的地的领域没有在源的映射字段,这就是为什么你正在寻找方式来忽略这些非映射的目标字段。

而不是实现和使用这些扩展方法,你可以简单地使用

 Mapper.CreateMap<destinationModel, sourceModel>(MemberList.Source); 

现在,automapper知道它只需要validation所有的源字段是映射的,而不是相反的。

从AutoMapper 5.0开始, .TypeMap上的.TypeMap属性消失了,这意味着4.2解决scheme不再有效。 我已经创build了一个解决scheme,使用原始的function,但使用不同的语法:

 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)); } } 

这个问题已经有几年了,但是使用目前版本的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; } 

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()); 

请注意,明确映射每个属性是有好处的,因为当您忘记映射属性时,您将永远无法默默地find映射失败的问题。

也许在你的情况下,忽略所有其他成员,并添加一个TODO回来,并在这个class的变化频率定下来之后明确这些是明智的。

对于那些在4.2.0及以上版本中使用非静态API的人,可以使用下面的扩展方法(在这里可以在AutoMapperExtensions类中find):

 // from http://stackoverflow.com/questions/954480/automapper-ignore-the-rest/6474397#6474397 public static IMappingExpression IgnoreAllNonExisting(this IMappingExpression expression) { foreach(var property in expression.TypeMap.GetUnmappedPropertyNames()) { expression.ForMember(property, opt => opt.Ignore()); } return expression; } 

这里最重要的是一旦静态API被移除,代码如Mapper.FindTypeMapFor将不再起作用,因此使用expression.TypeMap字段。

对于Automapper 5.0,为了跳过所有未映射的属性,您只需要放置

.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字段将被parsing,所有其他的将被跳过。 像魅力一样工作,似乎我们不再需要任何棘手的扩展!

我已经更新了Robert Schroeder对AutoMapper 4.2的回答。 使用非静态映射器configuration,我们不能使用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; } 

您希望如何指定某些成员被忽略? 是否有您想申请的惯例,基础类别或属性? 一旦你明确指定了所有的映射,我不确定你会从AutoMapper中获得什么价值。

这似乎是一个古老的问题,但认为我会发布我的答案给其他人看起来像我一样。

我使用ConstructUsing,与ForAllMembers结合的对象初始值设定项忽略例如

  Mapper.CreateMap<Source, Target>() .ConstructUsing( f => new Target { PropVal1 = f.PropVal1, PropObj2 = Map<PropObj2Class>(f.PropObj2), PropVal4 = f.PropVal4 }) .ForAllMembers(a => a.Ignore()); 

关于忽略许多成员的唯一信息是这个线程 – http://groups.google.com/group/automapper-users/browse_thread/thread/9928ce9f2ffa641f 。 我认为你可以使用ProvideCommonBaseClassConfiguration中的技巧忽略类似类的常见属性。
而且没有关于“忽略其余”function的信息。 我已经看过以前的代码,在我看来,添加这样的function将是非常非常困难的。 你也可以尝试使用一些属性,并用它忽略属性标记,并添加一些通用/通用代码来忽略所有标记的属性。

在3.3.1版本中,您只需使用IgnoreAllPropertiesWithAnInaccessibleSetter()IgnoreAllSourcePropertiesWithAnInaccessibleSetter()方法即可。

您可以使用ForAllMembers,而不是像这样只需要覆盖

 public static IMappingExpression<TSource, TDest> IgnoreAll<TSource, TDest>(this IMappingExpression<TSource, TDest> expression) { expression.ForAllMembers(opt => opt.Ignore()); return expression; } 

要小心,它会忽略所有,如果你不添加自定义映射,他们已经被忽略,将无法正常工作

另外,我想说,如果你有unit testing的AutoMapper。 你testing所有的属性映射正确的所有模型,你不应该使用这种扩展方法

你应该写明确的忽略

我知道这是一个古老的问题,但@jmoerdyk在你的问题:

你将如何在configuration文件中的链接的CreateMap()expression式中使用它?

你可以在Profile ctor中使用这个答案

 this.IgnoreUnmapped(); CreateMap<TSource, Tdestination>(MemberList.Destination) .ForMember(dest => dest.SomeProp, opt => opt.MapFrom(src => src.OtherProp));