如何在AutoMapper中全局使用Ignore?

3

目前的情况如下所示。 DestinationA 和 DestinationB 都是从某个 DestinationBase 类派生出来的。我需要忽略所有这些派生目标类的共同属性。有没有一种方法可以在不必为所有派生目标类重复此操作的情况下,全局地应用这些忽略选项呢?

Mapper.CreateMap<SourceA, DestinationA>()
      .ForMember(d => d.PropA, opt => opt.Ignore())
      .ForMember(d => d.PropB, opt => opt.Ignore())
      .ForMember(d => d.PropC, opt => opt.Ignore());

Mapper.CreateMap<SourceB, DestinationB>()
      .ForMember(d => d.PropA, opt => opt.Ignore())
      .ForMember(d => d.PropB, opt => opt.Ignore())
      .ForMember(d => d.PropC, opt => opt.Ignore());

我期望的是这样的效果:
Mapper.CreateMap<DestinationBase>().ForAllSource()
      .ForMember(d => d.PropA, opt => opt.Ignore())
      .ForMember(d => d.PropB, opt => opt.Ignore())
      .ForMember(d => d.PropC, opt => opt.Ignore());
5个回答

3
您可以全局忽略所有未映射的属性。 虽然这与Automapper的主要优点相矛盾,但只允许进行显式映射: 这是针对Automapper 6的:
    var mapperConfiguration = new MapperConfiguration(cfg =>
    {
        cfg.AddProfile(new MyProfile());
        // ignore all unmapped properties globally
        cfg.ForAllMaps((map, exp) => exp.ForAllOtherMembers(opt => opt.Ignore()));
    });

2
现在有一种名为FindTypeMapFor的方法,可以使这个扩展方法变得更小(并且更高效?):
public static IMappingExpression<TSource, TDestination> IgnoreAllNonMapped<TSource, TDestination>(this IMappingExpression<TSource, TDestination> expression)
    {
        foreach (var property in Mapper.FindTypeMapFor<TSource, TDestination>().GetUnmappedPropertyNames())
        {
            expression.ForMember(property, opt => opt.Ignore());
        }
        return expression;
    }

Automapper 8不包含FindTypeMapFor,看起来AM发展得如此之快,所有答案都是无用的。我有一种感觉,Automapper正在变得无用。 - Pawel Cioch

2

我曾经遇到过同样的问题,在寻求帮助时发现了这个旧问题。最终,我想出了以下解决方案。或许对其他人也有所帮助...

我有几个从基类派生出来的类。我想要排除基类的一个属性在任何派生自该基类的类的所有映射中。在创建我的映射之后(没有指定任何忽略选项),我执行以下操作:

foreach(var map in Mapper.GetAllTypeMaps())
{
    if (typeof(MyBaseClass).IsAssignableFrom(map.DestinationType))
    {
        var propInfo = map.DestinationType.GetProperty("PropertyToIgnore");
        if (propInfo != null) {
            map.FindOrCreatePropertyMapFor(new AutoMapper.Impl.PropertyAccessor(propInfo)).Ignore();
        }
    }
}

这有点暴力,因为我需要循环遍历所有类型映射,但它可以完成任务。

编辑:在if语句中添加了一个丢失的{


非常感谢...在搜索了几个小时后,您的解决方案为我节省了时间。 - Alexander Talavari
不错的解决方案。这肯定比手动忽略每个定义的映射属性要好得多。我想知道AutoMapper是否有任何官方解决方案计划。 - Squall
AutoMapper的版本是多少?我遇到了错误,GetAllTypeMapsImpl不存在。 - M Kenyon II

0

在这里查看schdr的IgnoreAllNonExisting()扩展:
AutoMapper:"忽略其余部分"?

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

谢谢,Rami。那真的帮了我很多。但我仍然认为这很危险,因为它不仅忽略你定义的属性,还忽略了所有未映射的属性。也许我需要稍微调整一下它。谢谢。 - gdenuf
@Nay 是的,我也做了类似的事情,在产品中记录任何值时我们会静默地记录下来,然后在本地构建中让它崩溃。 - Anicho

0

我不确定是哪个版本添加了属性,但现在你可以这样做。文档

[Ignore]
public string Property { get; set; }

这种方法的问题在于,您会在域实体之间泄漏AutoMapper实现,这并不好。

更好的方法似乎是在全局上设置 MapperConfiguration 上的过滤器,通过定义自己的 ShouldMapProperty 委托或将条件附加到默认实现。文档

var configuration = new MapperConfiguration(cfg =>
{
    cfg.ShouldMapField = ...;

    cfg.ShouldMapProperty = ...;
});

目前的默认实现在此处here。值得注意的是,如果未指定,默认实现ShouldMapProperty将会回退到p => p.IsPublic()。因此,您可以执行p => p.IsPublic() && p.DeclaringType != typeof(SomeBaseType) && p.Name == nameof(SomeBaseType.SomePropertyToIgnore)


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接