忽略使用 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<Foo, Bar>().ForMember(x => x.Blarg, opt => 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<Foo, Bar>().ForSourceMember(x => x.Blarg, opt => opt.Ignore());
可能有用
@***eth 你不是说:CreateMap<SourceType, DestType> (MemberList.Source).ForSourceMember(x => x.MySourceProperty, opt => 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 => 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 中返回一个选择器数组,然后使用 foreach
或 Select()
映射到每个选择器上,不过看起来可能不会那么混乱。跨度>
感谢@Steve Rukuts,对于任何正在寻找忽略源成员的扩展方法的人,您可以使用这个公共静态 IMappingExpressionReverseMap
是如何工作的? 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 IMappingExpressionIgnore()
不存在于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
提供谓词并有条件地选择要映射的属性。 ShouldMapField
和 ShouldMapMethod
属性也可用。
用法:
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