【问题标题】:How to ignore all destination members, except the ones that are mapped? [duplicate]如何忽略所有目标成员,除了映射的成员? [复制]
【发布时间】:2011-05-21 00:52:02
【问题描述】:

有没有办法做到这一点?我们有一个从三种不同类型映射的 SummaryDto,当我们为每种类型创建映射时,未映射的道具会引发错误。摘要 dto 上有大约 35 个属性。对每一个都使用 Ignore() 选项太麻烦了。是否存在全局忽略?类似的东西

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

【问题讨论】:

  • 这似乎是一件好事,但是,即使您的 DTO 上有 35 个属性,如果您使用的是AutoMapper.Mapper.AssertConfigurationIsValid();,那么您将来可能会忘记映射属性这可能会导致问题。我会谨慎使用
  • 从 5.0+ 版开始,您可以使用:.ForAllOtherMembers(m =&gt; m.Ignore())。见例子here
  • 在这种情况下,我只需要编写一个自定义映射器。 Automapper 仅在您有许多相同名称和类型的列(或能够在类型之间一致映射类型)时才有用。如果您只对众多列中的几列感兴趣,那么 AutoMapper 不是最佳解决方案。

标签: c# automapper


【解决方案1】:

这对我有用:

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 =&gt; 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));

【讨论】:

  • 这是删除和忽略常规映射。有没有办法保留传统的映射?
  • @JoaoLeme 我认为你需要决定你想要完成什么。忽略所有成员应该很少使用。我不确定 AutoMapper 如何确定如何保留您所谓的“常规映射”,但排除未映射的。我认为您最好在映射中明确说明您需要处理哪些成员 - 或 - 使用 IgnoreAllUnmapped 扩展,然后指定您只希望映射明确定义的成员。也许你需要完成的一个例子可以说明你为什么要问这个特定的问题。
  • @JoaoLeme 你也可以看看这个答案 - AutoMapper IgnoreTheRest - 这是 Edward Brey 在回答这个问题时指出的。
  • @JoaoLeme 只是我对此的看法,但如果您的域模型只需要 100 个属性中的几个,那么我会接受一些重复行而不是引入边缘案例扩展方法.
  • 从 5.0.0 开始这不起作用。您需要使用ForAllOtherMembers(opt =&gt; opt.Ignore()); 完成,不要使用ForAllMembers
【解决方案2】:

我也为这个问题苦苦挣扎了很长一段时间,或者至少是一个类似的问题。我有一个类,上面有很多属性(大约 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 返回映射表达式,因为那样可以正常链接。
  • 你也可以在最后使用 ForAllOtherMembers 并链接它。
  • @maracuja-juice 不,你不能! ForAllMembers 将忽略您已经映射的字段
  • @JerrySmith 这不是想要达到的目的吗? 1. 配置您要映射/自定义的字段 2. 使用 ForAllOtherMembers 忽略其他所有内容
  • @maracuja-juice 这不会像你描述的那样起作用
【解决方案3】:

为避免显式指定映射属性,您可以使用IgnoreAllNonExisting。它会忽略任何没有映射源属性的目标属性。

【讨论】:

    【解决方案4】:

    尝试在您的情况下使用.ConvertUsing(),例如

    CreateMap<Source,Target>()
     .ConvertUsing(converter=> new Target(){
    P1 = converter.P1,
    ....
    });
    

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

    【讨论】:

    • 这不起作用,所有其他字段都不会被忽略,它们只是用默认值填充
    • 因为我正在实例化一个新对象(目标),所以我希望忽略的属性具有它们的默认值,所以这很好。
    【解决方案5】:

    为 ForAllMembers 方法提供流畅语法的扩展方法:

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

    用法:

    对 IgnoreAllMembers 的调用必须在对 ForMember 的调用之前。

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

    【讨论】:

    • .ForAllMembers(opt => opt.Ignore());可以加在最后吗?
    猜你喜欢
    • 1970-01-01
    • 2017-10-12
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多