忽略使用 Automapper 映射一个属性

Posted

技术标签:

【中文标题】忽略使用 Automapper 映射一个属性【英文标题】:Ignore mapping one property with Automapper 【发布时间】:2011-06-26 15:35:55 【问题描述】:

我正在使用 Automapper,我有以下情况: 类 OrderModel 有一个名为“ProductName”的属性,该属性不在数据库中。 因此,当我尝试使用以下方法进行映射时:

Mapper.CreateMap<OrderModel, Orders>(); 

它会产生一个异常:

“Project.ViewModels.OrderModel 上的以下 1 个属性未映射:'ProductName'

我在AutoMapper's Wiki for Projections 阅读了相反的情况(额外的属性在目标上,而不是在我的情况下的源中)

如何避免自动映射器对该属性进行映射?

【问题讨论】:

Automapper 不能这样工作。它只关心目标对象的属性。 src 可以包含 100 个额外的属性——Automapper 只映射 dest 属性。必须有其他原因导致映射异常。你能发布一些不起作用的代码吗? 它会自动执行您的要求。发布一些代码以澄清 看看下面的帖子,这些可能对你有帮助***.com/questions/4456519/…***.com/questions/4052579/… @Patrick AutoMapper 在分析方法/属性名称方面做了一些技巧。即使目标上没有完全匹配,源上的某个属性也可能被无意映射。这就是为什么有一个 ForSourceMember(...Ignore()) 来防止这种情况发生的原因。 【参考方案1】:

来自 Jimmy Bogard:CreateMap&lt;Foo, Bar&gt;().ForMember(x =&gt; x.Blarg, opt =&gt; opt.Ignore());

它在one of the comments at his blog。

更新(来自Jamie's 2019 年 1 月 4 日 11:11 评论:)

在 ForSourceMember 中,

Ignore 已替换为 DoNotValidate: https://github.com/AutoMapper/AutoMapper/blob/master/docs/8.0-Upgrade-Guide.md

【讨论】:

另外,CreateMap&lt;Foo, Bar&gt;().ForSourceMember(x =&gt; x.Blarg, opt =&gt; opt.Ignore()); 可能有用 @***eth 你不是说:CreateMap&lt;SourceType, DestType&gt; (MemberList.Source).ForSourceMember(x =&gt; x.MySourceProperty, opt =&gt; opt.DoNotValidate()) 吗? Ignore 已被 ForSourceMember 中的 DoNotValidate 替换:github.com/AutoMapper/AutoMapper/blob/master/docs/… @Jamie @monty - 我开始更新这个:你的评论,但看起来语法更改只影响投影情况(需要忽略源属性)。 OP 的请求是忽略目标属性,因此,Ignore() 仍然是正确的语法。这是因为Ignore 的语法更改是在ISourceMemberConfigurationExpression 接口上进行的,而不是在不相交的IMemberConfigurationExpression`3 接口上进行的。 @Franva ForMember() 实际上是“ForDestinationMember()”【参考方案2】:

我可能有点完美主义者;我不太喜欢ForMember(..., x =&gt; x.Ignore()) 语法。这是一件小事,但对我来说很重要。我写了这个扩展方法让它更好一点:

public static IMappingExpression<TSource, TDestination> Ignore<TSource, TDestination>(
    this IMappingExpression<TSource, TDestination> map,
    Expression<Func<TDestination, object>> selector)

    map.ForMember(selector, config => config.Ignore());
    return map;

可以这样使用:

Mapper.CreateMap<JsonRecord, DatabaseRecord>()
        .Ignore(record => record.Field)
        .Ignore(record => record.AnotherField)
        .Ignore(record => record.Etc);

您也可以重写它以使用 params,但我不喜欢带有大量 lambda 的方法的外观。

【讨论】:

我知道这超出了最初的问题,但我真的很喜欢这个答案,它干净、易于阅读、立即理解并且易于重复使用 关于 params:您可以从单个 lambda 中返回一个选择器数组,然后使用 foreachSelect() 映射到每个选择器上,不过看起来可能不会那么混乱。跨度> 感谢@Steve Rukuts,对于任何正在寻找忽略源成员的扩展方法的人,您可以使用这个公共静态 IMappingExpression IgnoreSourceValidation(这个 IMappingExpression map, Expression> 选择器) map.ForSourceMember(selector, config => config.DoNotValidate());返回地图; ReverseMap 是如何工作的? ReverseMap().ForPath(... 我想我更愿意将其命名为 IgnoreMember(),但扩展名很棒!【参考方案3】:

你可以这样做:

conf.CreateMap<SourceType, DestinationType>()
   .ForSourceMember(x => x.SourceProperty, y => y.Ignore());

或者,在最新版本的 Automapper 中,您只是想告诉 Automapper 不验证字段

conf.CreateMap<SourceType, DestinationType>()
   .ForSourceMember(x => x.SourceProperty, y => y.DoNotValidate());

【讨论】:

automapper 是否有 ForSourceMember 扩展? 我目前正在这样做,但最好不必创建所有这些忽略...:/ 对于问题中给出的场景,这应该是公认的答案。当前接受的答案忽略了目标对象中的属性映射。这个问题是关于忽略源对象中的映射。 对于任何正在寻找扩展方法的人 public static IMappingExpression IgnoreSourceValidation( this IMappingExpression map, Expression> 选择器) map.ForSourceMember(selector, config => config.DoNotValidate());返回地图; Ignore() 不存在于ForSourceMember() 扩展中。正如@JasonDias 所说,它应该是DoNotValidate()。至少在最新版本的 automapper 中。【参考方案4】:

现在(AutoMapper 2.0)有一个IgnoreMap 属性,我将使用它而不是恕我直言的流利语法。

【讨论】:

忽略属性会通过您的应用程序泄漏自动映射器。 AutoMapper 是我不介意到处泄漏的一件事。 ;) 您可以随时考虑派生IgnoreMapAttribute 这是忽略跨多个对象继承的基本属性的好方法。不必在每个映射配置中忽略它。 IgnoreMap 已被删除。 docs.automapper.org/en/latest/…【参考方案5】:

对于任何试图自动执行此操作的人,您可以使用该扩展方法来忽略目标类型上不存在的属性:

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

感谢 Can Gencer 的提示 :)

来源: http://cangencer.wordpress.com/2011/06/08/auto-ignore-non-existing-properties-with-automapper/

【讨论】:

仅供参考:从***.com/questions/4052579/…合并 这在注入 IMapper 时不起作用。最新版本的 AutoMapper 中不存在 Mapper.GetAllTypeMaps。此外,当我在 AutoMapper.Profile 中设置我的地图然后注入 IMapper 时,我得到了这个异常“映射器未初始化。使用适当的配置调用初始化。如果您尝试通过容器或其他方式使用映射器实例,请确保您没有对静态 Mapper.Map 方法的任何调用,如果您使用 ProjectTo 或 UseAsDataSource 扩展方法,请确保传入适当的 IConfigurationProvider 实例。" 我刚收到'Mapper' does not contain a definition for 'GetAllTypeMaps' [DSSTools] .. @Bassie 使用 Mapper.Configuration.GetAllTypeMaps() source【参考方案6】:

将视图模型映射回域模型时,简单地验证源成员列表而不是目标成员列表会更简洁

Mapper.CreateMap<OrderModel, Orders>(MemberList.Source); 

现在我的映射验证不会失败,每次我向域类添加属性时都需要另一个 Ignore()

【讨论】:

这就是我要找的东西,在仅从更简单的 DTO 修改域对象属性的子集时非常有用。 这是答案,孩子们,把那个官方说出来,这样新手就不会被迷惑了【参考方案7】:

可以在需要忽略的属性上使用 IgnoreAttribute

【讨论】:

来自IgnoreMapAttribute[IgnoreMap]【参考方案8】:

也可以像这样忽略全局属性:

    使用映射器配置中的AddGlobalIgnore(string propertyNameStartingWith) 方法忽略名称以指定字符串开头的属性。 使用ShouldMapProperty 提供谓词并有条件地选择要映射的属性。 ShouldMapFieldShouldMapMethod 属性也可用。

用法:

public class MappingProfile : Profile

    public MappingProfile()
    
        // other configs...

        AddGlobalIgnore("foo")); // this will ignore properties with name starting with "foo"
        ShouldMapProperty = p => p.Name != "bar"; // this will ignore properties with name "bar"
    

或者:

var config = new MapperConfiguration(cfg => 
    // other configs...
    cfg.AddGlobalIgnore("foo"); // way 1
    cfg.ShouldMapProperty = p => p.Name != "bar"; // way 2
);

【讨论】:

【参考方案9】:

大家好,请使用它,它工作正常...对于自动映射器,在 C# 中使用多个 .ForMember

        if (promotionCode.Any())
        
            Mapper.Reset();
            Mapper.CreateMap<PromotionCode, PromotionCodeEntity>().ForMember(d => d.serverTime, o => o.MapFrom(s => s.promotionCodeId == null ? "date" : String.Format("0:dd/MM/yyyy h:mm:ss tt", DateTime.UtcNow.AddHours(7.0))))
                .ForMember(d => d.day, p => p.MapFrom(s => s.code != "" ? LeftTime(Convert.ToInt32(s.quantity), Convert.ToString(s.expiryDate), Convert.ToString(DateTime.UtcNow.AddHours(7.0))) : "Day"))
                .ForMember(d => d.subCategoryname, o => o.MapFrom(s => s.subCategoryId == 0 ? "" : Convert.ToString(subCategory.Where(z => z.subCategoryId.Equals(s.subCategoryId)).FirstOrDefault().subCategoryName)))
                .ForMember(d => d.optionalCategoryName, o => o.MapFrom(s => s.optCategoryId == 0 ? "" : Convert.ToString(optionalCategory.Where(z => z.optCategoryId.Equals(s.optCategoryId)).FirstOrDefault().optCategoryName)))
                .ForMember(d => d.logoImg, o => o.MapFrom(s => s.vendorId == 0 ? "" : Convert.ToString(vendorImg.Where(z => z.vendorId.Equals(s.vendorId)).FirstOrDefault().logoImg)))
                .ForMember(d => d.expiryDate, o => o.MapFrom(s => s.expiryDate == null ? "" : String.Format("0:dd/MM/yyyy h:mm:ss tt", s.expiryDate))); 
            var userPromotionModel = Mapper.Map<List<PromotionCode>, List<PromotionCodeEntity>>(promotionCode);
            return userPromotionModel;
        
        return null;

【讨论】:

以上是关于忽略使用 Automapper 映射一个属性的主要内容,如果未能解决你的问题,请参考以下文章

从源映射到现有目标时,AutoMapper 不会忽略 List

Automapper 忽略 null 值,但将空字符串映射到 null

Automapper忽略映射某字段的映射写法

Automapper 无法在单元测试项目中映射外键属性

Automapper:忽略目标属性的验证异常

C#AutoMapper 使用手册