我有一个如此定义的AutoMapper映射
CreateMap<DateTime?, DateString>()
.ForMember(dest => dest.Value, opt => opt.ResolveUsing(src => src.HasValue ? src.Value.ToString("yyyyMMdd") : String.Empty));
DateString
被定义为
public class DateString
{
public String Value { get; set; }
}
Value
属性是一个String
,它以yyyymmdd
格式表示日期,因此为了适应这种预期格式,我将表示为DateTime
类型的日期转换为String
格式。
上面的地图是从另一个这样定义的地图触发的
CreateMap<DateTimeDetails, PickupDetails>()
.ForMember(dest => dest.time, opt => opt.MapFrom(src => src));
DateTimeDetails
和PickupDetails
类定义为
public class DateTimeDetails
{
public Nullable<DateTime> Date { get; set; }
public String Time { get; set; }
public Int32 TimeZoneOffset { get; set; }
}
public class PickupDetails
{
public TimeString time { get; set; }
public DateString date { get; set; }
}
因此一般流程如下:
将DateTimeDetails
转换为PickupDetails
时,属性PickupDetails.date
和DateTimeDetails.Date
自动匹配,而无需使用.ForMember()
和.MapFrom()
,并且触发DateTime? -> DateString
地图。
根据DateString.Value
源对象是否具有值,将yyyymmdd
属性设置为String.Empty
或Nullable<DateTime>
。
我遇到的问题是,如果我将TSource
的{{1}}映射为DateTime? -> DateString
或Nullable<DateTime>
为空,则AutoMapper无法识别{{ 1}}签名并映射DateTime?
属性。它将引发错误
<TSource, TDestination>
如果我将地图做得更明确
PickupDetails.date
尝试进入解析器的逻辑,我不会碰到解析器中任何地方的任何断点。
要使其正常工作,唯一的方法是将Error mapping types.
Mapping types:
DateTimeDetails -> PickupDetails
Type Map configuration:
DateTimeDetails -> PickupDetails
Property:
date
更改为不可空的CreateMap<DateTime?, DateString>()
.ForMember(dest => dest.Value, opt => opt.ResolveUsing(src =>
{
if (src.HasValue)
{
return src.Value.ToString("yyyyMMdd");
}
else
{
return String.Empty;
}
}));
类型,并实施TSource
检查而不是DateTime
检查在这样的三元声明中获得回报
!= null
AutoMapper将以这种格式识别Nullable<DateTime>.HasValue
签名,并自动从CreateMap<DateTime, DateString>()
.ForMember(dest => dest.Value, opt => opt.ResolveUsing(src => src != null ? src.ToString("yyyyMMdd") : String.Empty));
映射中映射<TSource, TDestination>
。
我看不到我要去哪里,为什么我的PickupDetails.date
地图的DateTimeDetails -> PickupDetails
不能是TSource
或DateTime? -> DateString
且必须是不能为空的Nullable<DateTime>
Here是该问题的存储库。该在线编译器无法运行AutoMapper V7.0.1,因此正在使用V6.2.2,并且6.2.2的行为仍然不正确,但与我在上面解释的7.0.1中所遇到的不一样在这篇文章中。
在Lucian Bargaoanu的帮助下,我想出了更多有关此映射正在发生的事情。以下是具有相同DateTime?
语句的同一映射的执行计划,唯一更改的是DateTime
对于使用.ForMember()
TSource
的地图,将执行if-else块来检查Nullable<DateTime>
属性。如果为null,则它不返回TSource
类的$src
实例,而仅返回指向它的指针,导致new
属性未设置为等于其类类型的空实例,这将让它包含TDestination
属性,以获取destObj.date
的完整访问路径,.Value
只是设置为null。
我不确定的是这是否是插入此destObj.date.Value
的.Net Core框架行为,请检查lambda是否正在使用destObj.date
变量,或者AutoMapper是否正在添加它。正如您在下面的右图所示的执行计划中所见的那样,我正在尝试自己处理if($src == null)
场景。但是到目前为止,我永远都不会到达那里。
我也不确定Nullable<T>
变量在整个AutoMapper中的作用,但是现在我的$src == null
映射出现$typeMapDestination
错误。
我在想这可能是因为Error mapping types.
块阻止了CreateMap<Nullable<DateTime>, DateString>()
变量被操纵/返回,因此if($src == null)
中指定的目标属性实际上从未被“映射”过因此会引发错误。
还有一个值得注意的行为是不可空的$typeMapDestination
映射,即使发送了空值,尽管下面的代码块也是如此
.ForMemeber()
某种原因导致尝试失败并跌至下面的两个catch块之一。 if / else块的DateTime -> DateString
部分将不会触发。并且$resolvedValue = .Try {
.If($src != null) {
.Call $src.ToString("yyyyMMdd")
} .Else {
System.String.Empty
}
} .Catch(System.NullReferenceException) {
.Default(System.String)
} .Catch(System.ArgumentNullException) {
.Default(System.String)
};
等于null,而不是else { System.String.Empty }
属性为destObj.date
的{{1}}新实例。