作企业管理软件很难避免与Microsoft Excel打交道,经常是软件作好了,客户要求说再作一个Excel导入功能。导入Excel数据的功能的难度不大,从Excel列数据栏位的取值,验证值,再导入到数据库表中。然而一直是在作重复工做,写过不可胜数的Excel导入程序,每次只是知足于问题解决,后来终于找到一个方法,实现通用的Excel数据导入。html
设计通用的Excel导入功能,第一个实现要求是不能依赖Excel,客户的电脑或服务器颇有可能没有安装Excel,因此微软的Office Interop一律不考虑。第二个实现要求是须要高度抽象化,也就是不依赖于具体的数据库表,这样实现了从具体表导入到通用表导入的抽象,可重复用的程度高。数据库
第一步是生成Excel模板文件,先看字段选择界面,传入一个数据库表,可枚举表的字段,供生成Excel模板文件:编程
这个功能的做用是生成Excel文件,供用户输入数据。由于表名是由不一样的功能窗体传递过来,实现了通用化的第一步。服务器
生成的Excel文件,再加上咱们要填写的数据,参考下面的表格。框架
Department.Dept | Department.Description |
R&D | 开发部 |
CAM | 编程 |
CNC | 计算机锣 |
EDM | 火花机 |
WC | 线切割 |
SG | 磨床 |
OM | 其它加工 |
PO | 打光 |
QC | 质量控制 |
ASSM | 模具装配 |
INJE | 注塑部 |
AM | 行政及管理 |
看Excel的表头,它包含字段定义,字段前面有加表,这样可支持主从表导入。ide
第二步是在上面的步骤生成的Excel文件中输入数据,再到这个界面中点击Import便可完成数据导入。ui
先来看一下,如何调用这个通用的导入界面功能:this
protected override void SetupImportTemplate(EntityImportArgument argument) { base.SetupImportTemplate(argument); List<string> columnsList; // EntityManager argument.EntityManager = this._departmentManager; // EntityName argument.RootEntity = EntityType.DepartmentEntity; #region HiddenColumns #endregion #region Required Columns, columns must be selected as export columns. #region Item columnsList = new List<string>(); columnsList.Add(DepartmentFields.Dept.Name); columnsList.Add(DepartmentFields.Description.Name); argument.RequiredColumns.Add(EntityType.DepartmentEntity, columnsList); #endregion #endregion }
先设计好上面要调用接口,代码中解释了如下几个重要的方法:编码
1 要导入表 ORM映射的好处是根据实体能够找到它映射的表,根据表也能够找到它映射的实体。要跑数据验证,必须经过实体的验证类来实现,这样节省了不少验证代码。spa
2 保存表的方法 Manager类实现了把Excel数据保存到数据库中,对于这样通用的结构,保存方法也必需要求方法名称高度一致,好比表名是SalesOrder,它映射的实体名称是SalesOrderEntity,则对应的保存方法必定是SaveSalesOrder,这是调用时的契约,由系统强制约定。
3 值验证 若是数据库没有作强制要求输入(可空null),可是逻辑上要求必定要输入值,则须要跑实体验证。
数据导入使用的的第三方类库是Infragistics Excel,首先打开Excel文件,读取第一行字段名和相应的值。
using Infragistics.Documents.Excel; // Load workbook with data Workbook workbook = Workbook.Load("department.xls"); Worksheet worksheet = workbook1.Worksheets["Sheet1"]; string columnName=worksheet.Rows[0].Cells[0].Value;
构造一个内存DataSet,根据第一列的字段定义,构造表结构,例如上面的Excel文件表格,咱们能够构造以下表
Department(Dept,Description)
从Excel文件中咱们只能获取字段名称信息,还须要链接到数据库中,获取字段的类型信息。
SELECT * FROM sys.columns WHERE object_id=OBJECT_ID('Department')
根据这个查询,完善前面的表定义结构,相似于这样。
Department(Dept nvarchar(8),Description nvarchar(40))
这个时候就能够作基本的数据类型验证了,好比表字段的类型是数字,但Excel中的值是字符串,可抛出异常。
经过了基本的类型验证以后,咱们还须要作逻辑验证,好比数据库中已经定义了R&D部门,第二次执行又插入一笔R&D的部门编码时,须要及时抛出异常,这种业务逻辑上的验证,借助于ORM框架的功能实现。
LLBL Gen Pro提供的实体类型定义,都匹配有一个验证类型,当发生值改变前,数据保存前或是删除前均可以跑验证,咱们将这种复杂的验证逻辑经过实体调用来完成。
根据前面Department表的定义 ,查找系统元数据可知道它映射的实体是DepartmentEntity,咱们根据数据表的值记录,构造DepartmentEntity,上面表格中的Excel数据有多行记录,则构造一个List<DepartmentEntity>,借助于反射,把内存数据库DataTale中的字段值(DataRow行)转化为实体(Entity对象)。网上有不少关于DataTable与List<Entity>转化的例子代码。
咱们在保存Department方法前,主动调用Department的验证类型:
DepartmentValidator validator = new DepartmentValidator();
validator.ValidateRequiredFields(department);
最后,调用EntityManager接口中的Save方法便可:
ReflectionHelper.InvokeMethod(entityManager,”SaveDepartment”, typeof(DepartmentEntity), _department);
这个过程当中,所操做的数据库对象是经过接口完成,实现了可扩展性,实际应用中还可导入主从表数据,须要加关联行关联Excel的每行数据之间的关系。
目前尚未实现导入三层表数据。