首页 > 代码库 > NPOI操作excel——利用反射机制,NPOI读取excel数据准确映射到数据库字段
NPOI操作excel——利用反射机制,NPOI读取excel数据准确映射到数据库字段
其实需求很明确,就是一大堆不一样的excel,每张excel对应数据库的一张表,我们需要提供用户上传excel,我们解析数据入库的功能实现。
那么,这就涉及到一个问题:我们可以读出excel的表头,但是怎么知道每个表头具体对应数据库里面的字段呢?
博主经过一段时间的思考与构思,想到一法:现在的情况是我们有excel表A,对应数据库表B,但是A与B具体属性字段的映射关系我们不知。那我们是不是可以有一个A到B的映射文件C呢?
我想,说到这,大家就很明了了...
第一步:为每张excel创建一个与数据库表对应的映射文件(xml配置文件),我们称之为规则集,当然,我们的需求是excel的列表头不变(顺序可换---原因请继续往下看)
<?xml version="1.0" encoding="utf-8" ?> <module> <add firstHeaderRow="5" lastHeaderRow="7" sheetCount="1" Supplementary="0" /> <add headerText="年份" propertyName="Year" dataType="System.Int32"/> <add headerText="国内生产总值" propertyName="GDPValue" dataType="System.double"/> <add headerText="第一产业" propertyName="PrimaryIndustryAmount" dataType="System.double"/> <add headerText="第二产业" propertyName="SecondaryIndustry_TotalAmount" dataType="System.double"/> <add headerText="工业" propertyName="SecondaryIndustry_Industry" dataType="System.double"/> <add headerText="建筑业" propertyName="SecondaryIndustry_Construction" dataType="System.double"/> <add headerText="第三产业" propertyName="ThirdIndustryAmount" dataType="System.double"/> <add headerText="人均国内生产总值(元)" propertyName="GDPPerPerson" dataType="System.double"/> </module>
当然,这个xml文件由于是我们自己定义的节点,所以每个单词的意义就不详细解释了。
附:excel原表如下:
其中【剔除行关键字】在后续详细代码中介绍,请继续关注微博。
表头含有层级结构,具体读取方法也在后续详细代码中介绍...今天之讲述设计思想与部分基础代码。
第二步:新建一个读取我们自己定义的xml文件的类 RegularXMLReaderService.cs:
public class RegularXMLReaderService : IRegularXMLReaderService { public List<Regular> GetXMLInfo(string xmlpath) { //xmlpath为xml的路径名称 var reader = new XmlTextReader(xmlpath); var doc = new XmlDocument(); //从指定的XMLReader加载XML文档 doc.Load(reader); var headerList = new List<Regular>(); foreach (XmlNode node in doc.DocumentElement.ChildNodes) { var header = new Regular(); if (node.Attributes["firstHeaderRow"] != null) header.HeaderRegular.Add("firstHeaderRow", int.Parse(node.Attributes["firstHeaderRow"].Value)); if (node.Attributes["lastHeaderRow"] != null) header.HeaderRegular.Add("lastHeaderRow", int.Parse(node.Attributes["lastHeaderRow"].Value)); if (node.Attributes["sheetCount"] != null) header.HeaderRegular.Add("sheetCount", int.Parse(node.Attributes["sheetCount"].Value)); if (node.Attributes["ExcelType"] != null) header.HeaderRegular.Add("ExcelType", int.Parse(node.Attributes["ExcelType"].Value)); if (node.Attributes["Supplementary"] != null) header.HeaderRegular.Add("Supplementary", int.Parse(node.Attributes["Supplementary"].Value)); if (node.Attributes["headerText"] != null) header.HeaderText = node.Attributes["headerText"].Value; if (node.Attributes["propertyName"] != null) header.PropertyName = node.Attributes["propertyName"].Value; if (node.Attributes["dataType"] != null) header.DataType = node.Attributes["dataType"].Value; headerList.Add(header); } return headerList; } }
这段代码相信大家都能看懂,不做详细解释。其中设计到一个规则集类Regular.cs
/// <summary> /// 模板规则类 /// </summary> public class Regular { /// <summary> /// 表头文本 --对应excel表头名称 /// </summary> public string HeaderText { set; get; } /// <summary> /// 属性名称 --对应数据库字段名称 /// </summary> public string PropertyName { set; get; } /// <summary> /// 数据类型 ---对应数据库字段类型(用作判断excel数据是否合法用) /// </summary> public string DataType { set; get; } private Dictionary<string, int> _regular = new Dictionary<string, int>(); /// <summary> /// 表头规则 --我们所定义的具体规则,如我们文中例子的起始行、结束行、表单数等等 /// </summary> public Dictionary<string, int> HeaderRegular { get { return _regular; } set { _regular = value; } } }
这个类根据具体需求可能会有所不同,具体随设计而改变。
第三步:创建一个解析excel数据的类(excel越多越复杂,实现就越困难),此处先假设已建好(详细代码请关注后续博客)
/// <summary> /// Excel表格检查与数据读取接口 /// </summary> public interface IExcelImportService { /// <summary> /// 初始化Excel数据及配置文件 /// </summary> /// <param name="filePath">Excel文件</param> /// <param name="xmlPath">配置文件</param> /// <param name="nullable">可以为空</param> void InitDataAndConfig(string filePath, string xmlPath, bool nullable); /// <summary> /// 综合验证Excel表格符合性 /// </summary> /// <param name="customValidate">某单元项自定义检验接口</param> /// <returns></returns> UploadExcelFileResult ValidateExcel(ISpecification<KeyValuePair<string, string>> customValidate); /// <summary> /// 导入EXCEL文件 /// </summary> /// <typeparam name="TableDTO">数据对象DTO</typeparam> /// <returns>EXCEL数据集合</returns> List<TableDTO> Import<TableDTO>(); /// <summary> /// 导入EXCEL 文件------矩阵类模板 /// 19.6-长江干线货物流量流向 /// 20.5-西江航运干线货物流量流向 /// </summary> /// <typeparam name="TableDTO"></typeparam> /// <returns></returns> List<TableDTO> ImportForMatrix<TableDTO>(); }
此处是已建好的解析excel接口。(具体实现请参考后续博客)
博主的设计理念是:用户上传一个excel后我们后台分三步走:
1、初始化数据(excel文件流、对应配置文件--我们的规则集xml文件、以及一些其他的配置参数)
2、验证excel里面的数据合格(通过验证表头可以判定用户是否错误上传excel文件,验证里面数据是否违规(格式错误等)等等需要验证的方面)。验证成功后返回基础表头、附加信息等数据让用户确认并提交;失败后提示具体失败原因,准确定位到失败数据行列数。
3、用户看到验证通过的返回结果,确认无误后点击提交,此时读取数据入库。
至此,我们整个解析读取入库excel的流程就完成了,重在设计规则类这个设计思想,其中涉及到很多具体实现的代码,请参考后续博客专题。