AutoMapper:在运行时读取Mapper配置?

时间:2018-04-02 01:26:21

标签: excel automapper datareader

如果我的任何AutoMapper术语不正确,请原谅我,我是图书馆的新手。

我的代码

我已创建此Map,目的是从IDataReaderPersonDto进行映射。代码效果很好,我可以从PersonDto生成IDataReader个对象。没问题。

var map = CreateMap<IDataReader, PersonDto>()
    .ForMember(o => o.FirstName, opt => opt.MapFrom(row => row["First Name"]))
    .ForMember(o => o.LastName, opt => opt.MapFrom(row => row["Last Name"]))
    .ForMember(o => o.Birthday, opt => opt.MapFrom(row => row["Date of Birth"]))

我的问题

我正在寻找一些方法来获取上面定义的map,然后取回字符串{“First Name”, “Last Name”, “Date of Birth”}

我为什么要这样做(我的目标是什么)

这一部分只是为了以防万一有人为什么我想要做上述事情而摸不着头脑。正如我所提到的,我是图书馆的新手,所以我不知道我要求的是否反对Automapper的用途。

我正在使用ExcelDataReader库从Excel电子表格中读取数据。 xlsx来自第三方供应商,每隔几个月他们就会更改xlsx的布局(重新排序/重命名标头)。他们不提供Web API或其他方式来获取数据。

更重要的是,标题行的位置是不可预测的。供应商在同一工作表上的数据上方插入图表。为了解决这个问题,我编写了一个给出头名称的函数,它将返回标题行的索引:

   string headerNames[] = {“First Name”, “Last Name” ...}
   int headerIndex = findHeaderRow(dataReader, headerNames)

我希望能够从AutoMapper配置中获取标题名称,以便我可以直接将它们提供给findHeaderRow,而无需显式定义字符串数组。

我可以像这样创建我的地图,但它对我来说闻起来很脆弱。

var map = CreateMap<IDataReader, PersonDto>()
    .ForMember(o => o.FirstName, opt => opt.MapFrom(row => row[headerNames[0]]))
    .ForMember(o => o.LastName, opt => opt.MapFrom(row => row[headerNames[1]]))

结论

最终,我想要的是,当这些不可避免的布局发生变化时,这个Excel导入代码很容易更新。我希望标题名称只在一个地方定义,我看到的最佳位置是AutoMapper配置。

1 个答案:

答案 0 :(得分:0)

这就是我想出的。它有效,我只是不知道它有多强大,或者是否有更好的方法来做到这一点。

public static string[] GetSourceColumnNames<TSource, TDestination>(MapperConfiguration config) {

    var maps = config.ResolveTypeMap(typeof(TSource), typeof(TDestination)).GetPropertyMaps();

    string[] columnNames = new string[maps.Length];

    for (int i = 0; i < maps.Length; i++)
    {
        var body = maps[i].CustomExpression.Body;

        if (body is IArgumentProvider)
        {
            var provider = (IArgumentProvider)body;
            if (provider.ArgumentCount > 0)
            {
                columnNames[i] = provider.GetArgument(0).ToString().Trim('"');
            }
        }
    }       
    return columnNames;
}