我有这样定义的映射:
Mapper.CreateMap<DsMyDataSet.TMyRow, MyRowDto>();
MyRowDto是TMyRow的1:1副本,但所有属性都是自动属性。
[global::System.Diagnostics.DebuggerNonUserCodeAttribute()]
[global::System.CodeDom.Compiler.GeneratedCodeAttribute("System.Data.Design.TypedDataSetGenerator", "4.0.0.0")]
public string PositionFolder{
get {
try {
return ((string)(this[this.tableTMyDataSet.PositionFolderColumn]));
}
catch (global::System.InvalidCastException e) {
throw new global::System.Data.StrongTypingException("The value for column 'PositionFolder' in table 'TMyDataSet' is DBNull.", e);
}
}
set {
this[this.tableTMyDataSet.PositionFolderColumn] = value;
}
}
当我打电话时:
DsMyDataSet.TMyRow row = ....;
AutoMapper.Mapper.Map<MyRowDto>(row);
我得到StrongTypeingException异常,因为列中的值为null。该属性可以为null,但强类型数据集不支持可为null的属性,因此必须调用IsNullable instea。我如何在AutoMapper中解决这个问题,以便进行映射(忽略错误并保留null值)?
我认为解决这个问题的最简单方法是使用IMemberConfigurationExpression<DsMyDataSet.TMyRow>.Condition()
方法并使用try-catch
块来检查访问源值是否抛出StrongTypingException
。
以下是您的代码最终的样子:
Mapper.CreateMap<DsMyDataSet.TMyRow, MyRowDto>()
.ForMember( target => target.PositionFolder,
options => options.Condition(source => {
try { return source.PositionFolder == source.PositionFolder; }
catch(StrongTypingException) { return false; }
});
如果这种情况很常见,那么您可以选择其他一些选项来避免为每个成员编写所有这些代码。
一种方法是使用扩展方法:
Mapper
.CreateMap<Row,RowDto>()
.ForMember( target => target.PositionFolder, options => options.IfSafeAgainst<Row,StrongTypingException>(source => source.PositionFolder) )
当以下内容在解决方案中时:
public static class AutoMapperSafeMemberAccessExtension
{
public static void IfSafeAgainst<T,TException>(this IMemberConfigurationExpression<T> options, Func<T,object> get)
where TException : Exception
{
return options.Condition(source => {
try { var value = get(source); return true; }
catch(TException) { return false; }
});
}
}
AutoMapper还有一些内置的可扩展性点,在这里也可以利用。我突然想到的几种可能性是:
定义自定义
IValueResolver
实现。解决方案中已经有一个类似的实现可以使用:NullReferenceExceptionSwallowingResolver
。您可能会复制该代码,然后只更改指定处理哪种异常的部分。配置文档在AutoMapper wiki上,但配置代码看起来像:Mapper.CreateMap<Row,RowDto>() .ForMember( target => target.PositionFolder, options => options.ResolveUsing<ExceptionSwallowingValueResolver<StrongTypingException>>());
使用此映射:
Mapper.CreateMap<DsMyDataSet.TMyRow, MyRowDto>()
.ForMember(s => s.PositionFolder, o => o.MapFrom(d => !d.IsPositionFolderNull() ? d.PositionFolder: null));
在Automapper的较新版本中,如果DataRow
属性是DBNull
,则通常可以通过使用IMemberConfigurationExpression<TSource, TDestination, TMember>.PreCondition()
:来阻止映射它们
var config = new MapperConfiguration(
cfg =>
{
cfg.CreateMap<DsMyDataSet.TMyRow, MyRowDto>();
cfg.ForAllMaps((typeMap, map) =>
{
map.ForAllMembers(opt =>
{
opt.PreCondition((src, context) =>
{
var row = src as DataRow;
if (row != null)
{
return !row.IsNull(opt.DestinationMember.Name);
}
return true;
});
});
});
});