AutoMapper - 强类型数据集

时间:2013-11-21 14:23:09

标签: c# automapper strongly-typed-dataset

我有这样定义的映射:

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

我收到StrongTypingException异常,因为列中的值为null。该属性可以为空,但强类型数据集不支持可空属性,您必须调用IsNullable instea。 如何在AutoMapper中解决此问题,以便映射进行(忽略错误并保留空值)?

3 个答案:

答案 0 :(得分:2)

使用此映射:

Mapper.CreateMap<DsMyDataSet.TMyRow, MyRowDto>()
    .ForMember(s => s.PositionFolder, o => o.MapFrom(d => !d.IsPositionFolderNull() ? d.PositionFolder: null));

答案 1 :(得分:2)

我认为解决此问题的最简单方法是使用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还有一些内置的可扩展性点,也可以在这里使用。跳出来的几种可能性是:

  1. 定义自定义IValueResolver实施。您可以使用的解决方案中已有类似的实现:NullReferenceExceptionSwallowingResolver。您可以复制该代码,然后只需更改指定您正在使用的异常类型的部分。 Documentation for configuration is on the AutoMapper wiki,但配置代码如下所示:

    Mapper.CreateMap<Row,RowDto>()
      .ForMember( target => target.PositionFolder, 
            options => options.ResolveUsing<ExceptionSwallowingValueResolver<StrongTypingException>>());
    

答案 2 :(得分:0)

在较新版本的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;
                      });
                  });
              });
          });