![](/img/trans.png)
[英]Do I need to write all the properties explicitly when I am using AutoMapper, if these properties have the same name?
[英]Why do I have to Ignore all other properties in AutoMapper when using records?
public record Destination(double X, double Y);
public struct Source
{
public double X { get; set; }
public Potato Potato { get; set; }
public double Z { get; set; }
}
public struct Potato
{
public double Y { get; set; }
}
public MappingProfile()
{
CreateMap<Source, Destination>();
.ForCtorParam(nameof(Destination.Y), e => e.MapFrom(x => x.Potato.Y))
.ForAllOtherMembers(x => x.Ignore());
}
要将 map 源到目标,我需要手动 map 其中一个子项。 然而,automapper 将给出一个极其混乱的消息,说 Y 属性未映射。
Unmapped members were found. Review the types and members below.
Add a custom mapping expression, ignore, add a custom resolver, or modify the source/destination type
For no matching constructor, add a no-arg ctor, add optional arguments, or map all of the constructor parameters
==========================================================================================================
Source -> Destination (Destination member list)
Unmapped properties:
Y
我发现通过添加忽略所有其他成员的行,它会“解决”问题。 有没有更好的方法来防止发生此错误?
错误消息提到映射所有构造函数参数,但即使我添加.ForCtorParam(nameof(Destination.X), e => e.MapFrom(x => xX))
错误仍然发生。
这已在 11 中解决。因为您无法升级,所以您将不得不忽略所有这些属性。 问题是属性有设置器,在 AM 10 中,属性不被视为映射,即使它们已经通过构造函数映射。
另一种解决方案是使用不带 setter 的结构(或类)而不是record
。
我创建了以下 class 来帮助满足我的需求,因为我无法升级到更新的 AutoMapper 版本。
它是天真的,并假设记录上的所有属性都应映射到构造函数。
好处:
nameof
要使用它,请在MappingProfile
中:
new RecordMapBuilder<TSource, TDestination>(this)
.Map(x => x.Foo, x => x.Offset.Foo)
.Build();
public class RecordMapBuilder<TSource, TDestination>
{
private readonly Profile _profile;
private readonly bool _autoMapMatchingProperties;
private readonly Dictionary<string, Expression<Func<TSource, object>>> _ctorParamActions = new();
public RecordMapBuilder(Profile profile, bool autoMapMatchingProperties = true)
{
_profile = profile;
_autoMapMatchingProperties = autoMapMatchingProperties;
}
public void Build()
{
var map = _profile.CreateMap<TSource, TDestination>();
var unmappedDestinationProperties = new HashSet<string>(
typeof(TDestination)
.GetProperties()
.Where(e => !_ctorParamActions.ContainsKey(e.Name))
.Select(e => e.Name));
var sourceProperties = new HashSet<string>(typeof(TSource)
.GetProperties()
.Select(e => e.Name));
var mappableProperties = unmappedDestinationProperties.Intersect(sourceProperties).ToHashSet();
var unMappableProperties = unmappedDestinationProperties.Except(sourceProperties).ToHashSet();
if (unMappableProperties.Any())
{
var properties = string.Join(", ", unMappableProperties);
throw new InvalidOperationException($"Not all properties mapped for type {typeof(TSource)} -> {typeof(TDestination)}: {properties}");
}
if (_autoMapMatchingProperties)
{
foreach (var name in mappableProperties)
{
map.ForCtorParam(name, x => x.MapFrom(name));
}
}
foreach (var kv in _ctorParamActions)
{
map.ForCtorParam(kv.Key, x => x.MapFrom(kv.Value));
}
map.ForAllOtherMembers(x => x.Ignore());
}
public RecordMapBuilder<TSource, TDestination> Map(Expression<Func<TDestination, object>> destination, Expression<Func<TSource, object>> source)
{
var name = GetName(destination);
_ctorParamActions[name] = source;
return this;
}
private static string GetName(Expression<Func<TDestination, object>> destination)
{
{
if (destination.Body is UnaryExpression ue && ue.Operand is MemberExpression me)
{
return me.Member.Name;
}
}
{
if (destination.Body is MemberExpression me)
{
return me.Member.Name;
}
}
throw new InvalidOperationException($"Unhandled expression of type: {destination.Body.GetType()}");
}
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.