AutoMapper:“忽略其余部分”?

问题描述 投票:185回答:16

有没有办法告诉AutoMapper忽略所有属性,除了这些明确映射的人?

我有可能从外部改变外部DTO类和我想避免指定每个属性必须明确忽略,因为增加新的属性试图将它们映射到我自己的对象时,将打破功能(原因除外)。

.net automapper
16个回答
81
投票

这是一个扩展方法我写忽略了目的地的所有非现有属性。如果不知道它仍然是有用的,问题是两年多岁,但我跑进不必增加手册的很多忽略调用了同样的问题。

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()找出哪些属性未映射和经销商的忽略它们(如在回答这个问题)。似乎是一个更强大的解决方案给我。


10
投票

我已经更新了罗伯特·施罗德的答案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;
}

8
投票

你会如何喜欢指定某些成员被忽略?是否有约定,或基类,或属性你想申请?一旦你为明确指定所有映射的业务,我不知道你的价值会得到了AutoMapper的。


7
投票

这似乎是一个老问题,但认为我会张贴我的答案对任何人看起来像我。

我用ConstructUsing,加上ForAllMembers对象初始化忽略e.g

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

1
投票

约忽略许多成员的唯一infromation是这个线程 - http://groups.google.com/group/automapper-users/browse_thread/thread/9928ce9f2ffa641f。我想你可以使用ProvidingCommonBaseClassConfiguration使用的伎俩忽略了类似的类公共属性。 而且也没有关于“忽略其余”功能的信息。我看着面前的代码,并在我看来,这将是非常,非常难以增加这样的功能。你也可以尝试使用一些属性和标记它忽略性能,并添加一些通用/通用代码来忽略所有标记属性。


1
投票

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

你会如何在一个配置文件中的链接CreateMap()表达式中使用呢?

您可以使用此answer这样的配置文件里面构造函数

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

0
投票

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

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

要小心,它会不顾一切,如果你不会增加自定义映射关系,他们已经忽略了,不行的

另外,我想说,如果你有AutoMapper单元测试。你测试与正确映射所有属性所有车型,你不应该使用这样的扩展方法

你应该写忽略的明确


-2
投票

在3.3.1版本中,你根本无法qazxsw POI或qazxsw POI方法使用。


220
投票

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

205
投票

从我了解的问题是,有哪个没有在源,这就是为什么你正在寻找各种方法来忽略那些非映射目标字段映射领域的目标字段。

相反,实施和使用这些扩展方法,你可以简单地使用

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

现在automapper知道它仅需要验证所有的源字段映射周围而不是其他方式。

你也可以使用:

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

82
投票

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

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*/);
...

注:我使用的是2.0版AutoMapper。


58
投票

5.0.0-β-1 AutoMapper的介绍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回来修改这个类的频率之后,这些明确定下来。


43
投票

作为AutoMapper 5.0,上.TypeMapIMappingExpression属性消失了,这意味着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));
    }
}

17
投票

还有的是,几年以来,问题已经被问过,但这种扩展方法似乎更清洁对我来说,使用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;
}

16
投票

对于那些谁正在使用的non-static API在4.2.0版本及以上,下面的扩展方法(在here类中找到AutoMapperExtensions)可用于:

// 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领域。


16
投票

对于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字段将解决所有其他的将被跳过。工程就像一个魅力,似乎我们并不需要任何棘手的扩展了!

© www.soinside.com 2019 - 2024. All rights reserved.