如何忽略所有目标成员,除了那些已映射的成员?

89

有没有办法做到这一点?我们有一个SummaryDto,它从三种不同的类型映射而来,当我们为每种类型创建地图时,未映射的属性会抛出错误。摘要DTO上大约有35个属性。在每个属性上使用Ignore()选项太麻烦了。有全局忽略的方法吗?类似于

CreateMap<Source,Target>()
   .IgnoreAllUnmapped();

7
这似乎是一个不错的做法,但是,即使您的DTO上有35个属性,如果您使用AutoMapper.Mapper.AssertConfigurationIsValid();,那么您可能会在将来忘记映射某个属性,这可能会导致问题。我建议小心使用。 - CodeMonkeyKing
19
从版本5.0+开始,你可以使用:.ForAllOtherMembers(m => m.Ignore())。查看示例here - Shay
1
在这种情况下,我会编写一个自定义映射器。如果您有许多列具有相同的名称和类型(或能够在类型之间进行一致的映射),则Automapper非常有用。如果您只对许多列中的几列感兴趣,则AutoMapper不是最佳解决方案。 - matao
AutoMapper 11的解决方案是https://dev59.com/Z8Tra4cB1Zd3GeqP8XeF#73333328。 - Michael Freidgeim
5个回答

146

这对我有效:

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

由于ForAllMembers返回void,如果没有此扩展方法调用ForAllMembers(o => o.Ignore())将无法起作用。我们希望保持映射表达式可用以启用后续的映射:

CreateMap<Source, Destination>()
            .IgnoreAllUnmapped()
            .ForMember(d => d.Text, o => o.MapFrom(s => s.Name))
            .ForMember(d => d.Value, o => o.MapFrom(s => s.Id));

2
这将移除和忽略传统的映射。是否有一种方法可以保留传统的映射? - Joao Leme
2
@JoaoLeme 我认为你需要决定你想要实现什么目标。忽略所有成员应该很少使用。我不确定AutoMapper如何确定如何保留你所谓的“常规映射”,但排除未映射的内容。我认为你最好在映射中明确说明你需要处理哪些成员或使用IgnoreAllUnmapped扩展,然后指定你只想将明确定义的成员映射。也许一个你需要完成的示例可以说明为什么你提出了这个问题。 - CodeMonkeyKing
26
从5.0.0版本开始,这种方法已不再奏效。您需要以ForAllOtherMembers(opt => opt.Ignore());结尾,并且不要使用ForAllMembers - jsgoupil
3
AutoMapper 11已弃用ForAllOtherMembers :(AutoMapper 11已经停用ForAllOtherMembers方法。 - thepirat000
3
Automapper 11中唯一的选项是显式列出所有字段,因此配置文件会混杂着100多行无用代码。这太愚蠢了。Automapper的开发人员不想支持效率。 - Wouter
显示剩余3条评论

33

我也曾经遇到过类似的问题,或者说是相似的难题。我的一个类有很多属性(大约30个),但我只想映射其中的4个。添加26个忽略语句似乎有些疯狂(特别是当未来更改类时意味着必须更新它们时!)

最终我发现我可以告诉AutoMapper忽略一切,然后明确地添加我需要的属性。

// Create a map, store a reference to it in a local variable
var map = CreateMap<Source,Target>();

// Ignore all members
map.ForAllMembers(opt => opt.Ignore());

// Add mapping for P1
map.ForMember(dest => dest.P1, opt => opt.MapFrom( src => src.P1));

// Add other mappings...
map.ForMember(dest => dest.P2, opt => opt.MapFrom( src => src.P2));
map.ForMember(dest => dest.P3, opt => opt.MapFrom( src => src.P3));
map.ForMember(dest => dest.P4, opt => opt.MapFrom( src => src.P4));

如果你认为可以这样做(但不要这样做,因为它无法编译)那么你会被原谅:

// This won't compile
CreateMap<Source,Target>()
   .ForAllMembers(opt => opt.Ignore())
   .ForMember(dest => dest.P1, opt => opt.MapFrom( src => src.P1));

这不起作用的原因是ForAllMembers()方法不支持流畅的链接方式(至少在当前版本2.0中不支持)。
好消息是非链接版本确实可行。当然,唯一的注意事项是您需要明确告诉AutoMapper要映射哪些成员。我还没有找到一种简单的方法来同时使用隐含映射并忽略损坏的映射。

你不一定需要像那样在变量中存储map。如果您创建多个映射,则AutoMapper会更新现有映射(是的,可能不太直观,但这就是它的工作方式)。因此,在您的示例中,您可以调用CreateMap...Ignore(),然后CreateMap...ForMember()...ForMember()...而不会出现任何问题。我不确定为什么Jimmy决定不从ForAllMembers返回映射表达式,因为这将允许正常链接。 - julealgon
1
你也可以在末尾使用ForAllOtherMembers并链接它。 - maracuja-juice
@maracuja-juice 不行,你不能这么做!ForAllMembers 操作将会忽略已经映射的字段。 - Tsagana Nokhaeva
@JerrySmith 这不就是想要通过它来实现的吗?1. 配置您想要映射/自定义的字段2. 使用ForAllOtherMembers忽略其他所有内容 - maracuja-juice
@maracuja-juice,按照你描述的方式这样做不会起作用。 - Tsagana Nokhaeva
不适用于AutoMapper 11。 - thepirat000

5
为了避免需要明确指定映射属性,您可以使用IgnoreAllNonExisting。它会忽略任何目标属性没有映射源属性的情况。

3

ForAllMembers方法的流畅语法扩展方法:

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

用法:

在调用 ForMember 之前必须先调用 IgnoreAllMembers。

        CreateMap<LocationRevision, Dto.LocationAddressMap>()
            .IgnoreAllMembers()
            .ForMember(m => m.LocationId, opt => opt.MapFrom(src => src.Id))
            ;

可以在末尾添加.ForAllMembers(opt => opt.Ignore());吗? - Leszek P
@LeszekP 不行,因为ForAllMembers会覆盖所有先前的映射。 - thepirat000

2
尝试在你的情况下使用.ConvertUsing(),例如:
CreateMap<Source,Target>()
 .ConvertUsing(converter=> new Target(){
P1 = converter.P1,
....
});

因此,您可以描述您想在对象中拥有的所有属性,其他属性将被忽略。

1
这个不起作用,所有其他字段都不会被忽略,它们只是填充默认值。 - Para
由于我正在实例化一个新对象(Target),我希望被忽略的属性具有它们的默认值,所以这很好。 - DownChapel

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