Demo源码
背景
通过程序将excel导入到数据库中是一项非常常见的功能。通常的做法是:先将excel转成DataTable,然后将DataTable转换成List<T>,最终通过List<T>导入进数据库。
同时,一般的ExcelUtil基类也会提供类似List<T> GetEntityListFromFile<T>(string fileName)的实现,但是这些实现一般都是机械化地对应,缺少一些自定义的操作。
问题
在我的开发过程中,就导入excel这一块就碰到了以下的一些问题:
以上这些问题,仅仅通过基类提供的方法是无法实现的,所以本篇文章提供一种高度自定义的Excel导入通过模块的实现,期以解决以上问题。
Demo程序结构概览
ps:要下班了,今日就先发这么多,
大家可以先下Demo看一下,功能都实现了,有问题可以大家一起交流,
如果大家想知道具体流程,我就再添加。
实现思路
首先,需要明确的是我们的需求:
接下来,就简要讲述一下以上功能的实现:
/// <summary> /// 高度可扩展的excel导入 By Dean 20140320 /// 应用场景:1 需要支持实体类属性和excel中列的一对多关系 如excel中的列名是JHB、聚好币、PV时候,均认为映射到实体中的JHB字段 ///2 需要支持实体类属性和excel中列的多对一关系 如excel中只包含“名称”列,有同时填充实体类的Code & Name属性时,可以将Code属性也对应到“名称”列,然后写一个转换函数,通过“名称”从DB中取出Code再映射 /// 功 能:1 可以自动剔除全部为空的行 /// 2 能够自定义地设置将excel中的列映射到实体类上的哪个字段,以及映射的方法 /// 3 能够对excel中的数据的有效性进行自定义的检查 /// </summary> /// <typeparam name="Entity"></typeparam> public class ImportUtil<Entity> where Entity : new()
public ImportUtil(Dictionary<string, string> allColumns) { AllColumns = allColumns; }
//实体类列和excel列的对应关系 Dictionary<string, string> allColumns = new Dictionary<string, string> { {"ID","编号"}, {"StudentID","学生编号|学生ID"},{"StudentName","学生编号|学生ID"}, {"DisciplineID","学科编号"},{"DisciplineName","学科编号"}, {"Score","学科分数"}, {"MakeUpExamTime","补考日期"} };
该构造函数传入参数allColumns,是一个Dictionary<string,string>类型的,该参数实现了需求2,字典的Key是实体类Entity中的【属性名称】,字典的Value是excel中的【列名称】,使用|来支持excel的多列名。
/// <summary> /// 根据excel文件名获取实体类列表 《唯一向外部公开的接口》 /// </summary> /// <param name="fileName">excel文件名</param> /// <param name="errorInfo">导入过程中的任何错误信息都会放到这里面</param> /// <param name="converterFields">需要进行预定义类型转换的列</param> /// <param name="customConverts">需要进行自定义类型转换(key是实体类对应的列,value是包含excel中对应列的值和操作后的返回值的Func)</param> /// <param name="dataValidateChecks">在进行excel列映射到实体类之前,对excel列中的值进行的预检查</param> /// <returns>实体类列表</returns> public List<Entity> GetEntityList(string fileName, List<string> errorInfo, Dictionary<KnownDataType, List<string>> converterFields = null, Dictionary<string, Func<object, object>> customConverts = null, Dictionary<string, Func<object, string>> dataValidateChecks = null)
该方法有5个输入参数,其中fileName和errorInfo是必输的,方法最终返回的就是我们所需要的List<Entity>,方法的执行过程就是先通过excel的地址将excel导入称为DataTable,然后将DataTable转换成List<T>,在转换的过程中进行数据的有效性验证和数据值的类型转换。
下面简单介绍一下这5个参数:
//预定义类型转换 Dictionary<KnownDataType, List<string>> convertFields = new Dictionary<KnownDataType, List<string>> { {KnownDataType.Int, new List<string> {"ID", "StudentID", "DisciplineID"}}, {KnownDataType.Double, new List<string> {"Score"}} };
//自定义类型转换 Dictionary<string, Func<object, object>> customConverts = new Dictionary<string, Func<object, object>> { { "StudentName", currColumn => { int studentID; if (currColumn != null && int.TryParse(currColumn.ToString(), out studentID)) { var r = DataPool.EntireStudents.Find(c => c.ID == studentID); if (r != null) { return r.Name; } } return string.Empty; } }, { "MakeUpExamTime", currColumn => { DateTime colDateTime; if (currColumn != null && DateTime.TryParse(currColumn.ToString(), out colDateTime)) { return colDateTime; } return null; } } };
//excel列的数据有效性验证 以下完成了对excel中编号列的值必须为整数且不为空的验证的设定 Dictionary<string,Func<object,string>> dataValidateChecks = new Dictionary<string, Func<object, string>> { { "ID", currColumn => { int idInt; if (currColumn!=null&&int.TryParse(currColumn.ToString(),out idInt)) { return string.Empty; } return "ID不能为空且必须为整数"; } } };
//执行excel导入 var res = importUtil.GetEntityList(excelPath, errors, convertFields, customConverts, dataValidateChecks);
总结
以上就完成了一个excel的自定义导入的功能,谢谢。
Demo源码
新闻热点
疑难解答