Demo源码

背景

  通过程序将excel导入到数据库中是一项非常常见的功能。通常的做法是:先将excel转成DataTable,然后将DataTable转换成List<T>,最终通过List<T>导入进数据库。

  同时,一般的ExcelUtil基类也会提供类似List<T> GetEntityListFromFile<T>(string fileName)的实现,但是这些实现一般都是机械化地对应,缺少一些自定义的操作。

问题

  在我的开发过程中,就导入excel这一块就碰到了以下的一些问题:

  1.   excel中的列名可能不止一个(客户可能没有下载模板或者模板的版本不对,导致同一列可能有多个列名,例如【ID】和【编号】可能都对应实体类中的【ID】列)
  2.   excel中的列可能对应着实体类中的多个列(例如实体类中有【ID】、【Name】两个字段,而excel模板中只有【ID】,我们需要通过excel中的【ID】从数据库中找到Name值去填充实体类的【Name】)
  3.   需要对excel中某些数据的有效性做验证,包括但不限于“数据类型有效”,“数据在数据库中的存在性”,“数据在数据库中的状态有效”等等
  4.   需要对excel中的某些列进行自定义的映射(例如实体类和excel中都有【Status】,我们需要将excel中的【Status】写“1”和写“激活”的都填充实体类的【Status】为“1”)

  以上这些问题,仅仅通过基类提供的方法是无法实现的,所以本篇文章提供一种高度自定义的Excel导入通过模块的实现,期以解决以上问题。

Demo程序结构概览

  

  

ps:要下班了,今日就先发这么多,

  大家可以先下Demo看一下,功能都实现了,有问题可以大家一起交流,

  如果大家想知道具体流程,我就再添加。

实现思路

  首先,需要明确的是我们的需求:

  1. 使用c#技术,将excel导入到程序中,并以List<Entity>的形式进行存在
  2. 可以自定义excel的列名和Entity中属性的对应关系,支持excel中多个列名对应Entity中同一个属性,也支持Entity中的多个属性对应excel中的一个列名
  3. 可以自定义excel中列的值转换函数,假设excel中有“状态”列对应到Entity中的Status属性,在excel中的“状态”列中写【激活】或者【1】,最终都对应到Status的【true】
  4. 可以自定义excel中列的值有效性验证函数

  接下来,就简要讲述一下以上功能的实现:

  • 类【public class ImportUtil<Entity> where Entity : new()】实现了excel的导入功能,Entity为实体类类型
    /// <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()
  • ImportUtil类中有唯一的构造函数【public ImportUtil(Dictionary<string, string> allColumns)】
  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的多列名。

  • ImportUtil类中有唯一的对外公开的方法【public List<Entity> GetEntityList】
        /// <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个参数:

  1. fileName,string,需要导入的excel的地址;
  2. errorInfo,List<string>,导入过程中所发生的错误信息;
  3. convertFields,Dictionary<KnownDataType,List<string>>,预定义的类型转换;excel中的列都是object类型的,而Entity中的属性却是强类型的,对于Int,Decimal,Double,DateTime已经定义好了相关的转换函数,仅需将Entity属性名称传入,在进行DataTable转List<Entity>时就能够将对应Column的值进行预定义的类型转换
               //预定义类型转换
    Dictionary<KnownDataType, List<string>> convertFields = new Dictionary<KnownDataType, List<string>>
    {
    {KnownDataType.Int, new List<string> {"ID", "StudentID", "DisciplineID"}},
    {KnownDataType.Double, new List<string> {"Score"}}
    };
  4. customConverts,Dictionary<string,Func<object,object>>,自定义的类型转换;预定义的类型转换通常只是将excel中的列转成对应的类型或者给个默认值,是通用的操作,但是我们常常需要对excel中的列进行自定义的转换,例如:excel中有“编号”列,设置同时对应到Entity的“ID”、“Name”属性,而“ID”属性可以直接使用预定义转换完成,“Name”列则需要通过“编号”从数据库中找到“Name”再赋值给“Name”。因此,这时候我们需要自定义的转换。写法如下:
                //自定义类型转换
    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;
    }
    }
    };
  5. dataValidateChecks,Dictionary<string,Func<object,string>>,excel列的数据有效性验证,在Entity的每个属性的赋值之前都会先验证一下excel的数据是否有效,Key是要验证的属性的名字,Value是一个Func,输入参数就是excel的列值,返回的是string,验证通过时是string.Empty,验证不通过返回的是错误信息。写法如下:
                //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源码

通用的高度可扩展的Excel导入实现(附Demo)的更多相关文章

  1. excel 导入 下载模板 demo

    import org.apache.commons.beanutils.PropertyUtils;import org.apache.commons.lang3.StringUtils;import ...

  2. 解析大型.NET ERP系统 设计通用Microsoft Excel导入功能

    做企业管理软件很难避免与Microsoft Excel打交道,常常是软件做好了,客户要求说再做一个Excel导入功能.导入Excel数据的功能的难度不大,从Excel列数据栏位的取值,验证值,再导入到 ...

  3. 利用反射实现通用的excel导入导出

    如果一个项目中存在多种信息的导入导出,为了简化代码,就需要用反射实现通用的excel导入导出 实例代码如下: 1.创建一个 Book类,并编写set和get方法 package com.bean; p ...

  4. 一个基于POI的通用excel导入导出工具类的简单实现及使用方法

    前言: 最近PM来了一个需求,简单来说就是在录入数据时一条一条插入到系统显得非常麻烦,让我实现一个直接通过excel导入的方法一次性录入所有数据.网上关于excel导入导出的例子很多,但大多相互借鉴. ...

  5. Delphi Excel导入 的通用程序转载

    Delphi Excel导入 的通用程序 (-- ::)转载▼ 标签: it 分类: Delphi相关 步骤: 连excel(自己知道其格式,最好是没个字段在数据一一对应) 读excel数据,填入到数 ...

  6. SNF开发平台WinForm之十-Excel导入-SNF快速开发平台3.3-Spring.Net.Framework

    7.1运行效果: 2.Excel导入开发实现 2.1. 创建窗体,修改命名空间 新增的窗体命名“FrmImport表名”,这个导入窗口比较其它窗口会特殊一些,需要继承BaseFormImport父级窗 ...

  7. excel导入mssql数据库,支持excel2003--2010文件格式

    rt,简单的excel导入mssql.未做性能及海量数据优化,一般单表5000左右条数据导入适用. 源码非原创,来源于之前搜集整理,原作者无从考究,如有版权问题请留言注明. 看代码.前台页面是一个Fi ...

  8. ASP.NET MVC5+EF6+EasyUI 后台管理系统(63)-Excel导入和导出-自定义表模导入

    系列目录 前言 上一节使用了LinqToExcel和CloseXML对Excel表进行导入和导出的简单操作,大家可以跳转到上一节查看: ASP.NET MVC5+EF6+EasyUI 后台管理系统(6 ...

  9. Excel 导入到Datatable 中,再使用常规方法写入数据库

    首先呢?要看你的电脑的office版本,我的是office 2013 .为了使用oledb程序,需要安装一个引擎.名字为AccessDatabaseEngine.exe.这里不过多介绍了哦.它的数据库 ...

随机推荐

  1. 1044 拦截导弹 1999年NOIP全国联赛提高组 个人博客:attack.cf

    1044 拦截导弹 1999年NOIP全国联赛提高组 时间限制: 1 s 空间限制: 128000 KB 题目等级 : 黄金 Gold         题目描述 Description 某国为了防御敌 ...

  2. C++ 中函数后面跟const是什么意思

    问题:c++:void display( ) const 中的const是什么意思?简答:意思是除了表明了mutable的成员变量以外该类的其他的成员变量在这个函数内一律不能修改. 详细:加const ...

  3. 如何在Android Studio中导入JNI生成的.so库

    由于在原来的ADT的Eclipse环境中,用ndk_build工具生成了相应的各个.so库文件之后,eclipse工具就会自动把这些库导入到apk中.而Android Studio目前为止(0.86版 ...

  4. 【虚拟机-网络IP】使用 Powershell 设置 VNET 中的静态 IP

    本文包含以下内容 对已有虚机设置静态 Internal IP 取消对对已有虚机设置的静态 Internal IP 创建静态 Internal IP的虚机 使用中的注意点 请注意:以下操作需要下载最新版 ...

  5. Python+selenium之fixtures

    fixtures即可以表示测试用例的开始和结束,也可以表示测试类和测试模块的开始和结束. import unittest def setUpModule(): print("test mod ...

  6. 事务回滚 DEMO

    因为有些事物回滚  查询的时候 可能查出来空值 我们肯定不愿意把空值添加数据库里面 一般基本的是这么写 if (object_id('add_T_Disclose_DiscloseList', 'P' ...

  7. 转载 - 浅析我曾遇到的几个便宜VPS服务器

    本文来自:http://www.jianshu.com/p/7d8cfa87fa32 有些时候可能并不是我们工作和业务的需要,但是网上就是这么的邪门,如果看到便宜的衣服不去购买深怕自己吃亏.所以每年的 ...

  8. bzoj3209:3209: 花神的数论题

    觉得还是数位dp的那种解题形式但是没有认真的想,一下子就看题解.其实还是设置状态转移.一定要多思考啊f[i][j]=f[i-1][j]+g[i-1][j] g[i][j]=f[i-1][j-1]+g[ ...

  9. Contour Features 边界特征

    查找轮廓 findContours   cv2.findContours(image, mode, method[, contours[, hierarchy[, offset]]]) → image ...

  10. Ubuntu下手动安装NextCloud

    安装环境:阿里云VPS Ubuntu 16.04   一. 安装Apache2 sudo apt-get install apache2 安装完成后,浏览器访问http://your ip/,出现It ...