解析大型.NET ERP系统 设计通用Microsoft Excel导入功能
做企业管理软件很难避免与Microsoft Excel打交道,常常是软件做好了,客户要求说再做一个Excel导入功能。导入Excel数据的功能的难度不大,从Excel列数据栏位的取值,验证值,再导入到数据库表中。然而一直是在做重复工作,写过不计其数的Excel导入程序,每次只是满足于问题解决,后来终于找到一个方法,实现通用的Excel数据导入。
设计通用的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的表头,它包含字段定义,字段前面有加表,这样可支持主从表导入。
第二步是在上面的步骤生成的Excel文件中输入数据,再到这个界面中点击Import即可完成数据导入。
先来看一下,如何调用这个通用的导入界面功能:
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映射的好处是根据实体可以找到它映射的表,根据表也可以找到它映射的实体。要跑数据验证,必须通过实体的验证类来实现,这样节省了很多验证代码。
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的每行数据之间的关系。
目前还没有实现导入三层表数据。
解析大型.NET ERP系统 设计通用Microsoft Excel导入功能的更多相关文章
- 解析大型.NET ERP系统 设计异常处理模块
异常处理模块是大型系统必备的一个组件,精心设计的异常处理模块可提高系统的健壮性.下面从我理解的角度,谈谈异常处理的方方面面.我的设计仅仅限定于Windows Forms,供参考. 1 定义异常类型 . ...
- 解析大型.NET ERP系统 十三种界面设计模式
成熟的ERP系统的界面应该都是从模板中拷贝出来的,各类功能的界面有规律可遵循.软件界面设计模式化或是艺术性的创作,我认可前者,模式化的界面客户容易举一反三,降低学习门槛.除了一些小部分的功能界面设计特 ...
- 解析大型.NET ERP系统架构设计 Framework+ Application 设计模式
我对大型系统的理解,从数量上面来讲,源代码超过百万行以上,系统有超过300个以上的功能,从质量上来讲系统应该具备良好的可扩展性和可维护性,系统中的功能紧密关联.除去业务上的复杂性,如何设计这样的一个协 ...
- 解析大型.NET ERP系统 单据标准(新增,修改,删除,复制,打印)功能程序设计
ERP系统的单据具备标准的功能,这里的单据可翻译为Bill,Document,Entry,具备相似的工具条操作界面.通过设计可复用的基类,子类只需要继承基类窗体即可完成单据功能的程序设计.先看标准的销 ...
- 解析大型.NET ERP系统 权限模块设计与实现
权限模块是ERP系统的核心模块之一,完善的权限控制机制给系统增色不少.总结我接触过的权限模块,以享读者. 1 权限的简明定义 ERP权限管理用一句简单的话来说就是:谁 能否 做 那些 事. 文句 含义 ...
- 解析大型.NET ERP系统 通用附件管理功能
大型系统具备一个通用的附件管理功能,对于单据中无法清晰表达的字段,用一个附件图片或附件文档表示是最好的方法了.比如物料清单附加一张CAD图纸,销售订单评审功能中附加客户的各种表格,通用附件功能对系统起 ...
- 解析大型.NET ERP系统 业务逻辑设计与实现
根据近几年的制造业软件开发经验,以我开发人员的理解角度,简要说明功能(Feature)是如何设计与实现的,供参考. 因架构的不同,技术实现上会有所差异,我的经验仅限定于Windows Form程序. ...
- 解析大型.NET ERP系统 分布式应用模式设计与实现
C/S架构的应用程序,将一些复杂的计算逻辑由客户端转移到服务器端可以改善性能,同时也为了其它方面的控制..NET Remoting在局域网内调用的性能相当不错.ERP系统中基于.NET Remotin ...
- 解析大型.NET ERP系统 20条数据库设计规范
数据库设计规范是个技术含量相对低的话题,只需要对标准和规范的坚持即可做到.当系统越来越庞大,严格控制数据库的设计人员,并且有一份规范书供执行参考.在程序框架中,也有一份强制性的约定,当不遵守规范时报错 ...
随机推荐
- ABP文档 - 异常处理
文档目录 本节内容: 简介 启用错误处理 非AJAX请求 显示异常 UserFriendlyException Error 模型 AJAX 请求 异常事件 简介 这个文档针对Asp.net Mvc和W ...
- x:bind不支持样式文件 或 此Xaml文件必须又代码隐藏类才能使用{x:Bind} 解决办法
这两天学习UWP开发,发现一个很有趣的问题,就是我题目中的描述的. 我习惯了在ResourceDictionary中写样式文件,但是发现用x:Bind时会有问题 如果是写在Style里,则提示 “x: ...
- Android 自定义 attr
好纠结,弄了一个下午老是报错如是总结一下安卓自定视图和自定义属性. (一)自定义属性 在Values文件下建立一个attrs.xml文件,attr的format可以参考:http://www.cnbl ...
- 使用Zabbix监控Oracle数据库
Orabbix介绍 监控Oracle数据库我们需要安装第三方提供的Zabbix插件,我们先测试比较有名的Orabbix,http://www.smartmarmot.com/product/orabb ...
- Lambda
Lambda Lambda 表达式是一种可用于创建委托或表达式目录树类型的匿名函数. 通过使用 lambda 表达式,可作为参数传递或作为函数调用值返回的本地函数. Lambda 表达式对于编写 LI ...
- 【夯实PHP基础】PHP常用类和函数总结
本文地址 代码提纲: 1. 字符串处理类及函数 2. 数组处理类及函数 3 .web处理类及函数 将常用的PHP的类和函数总结到这里,主要是 自己用过的,比较有感觉. 1. [字符串处理] 1)[ut ...
- 简述我的SOA服务治理
SOA服务治理 1.解决业务部门服务冲突和纠纷2.版本定义与版本管理3.服务备案与服务管理4.业务监督与服务监控 SOA的战略目的 一.业务价值胜过技术策略 二.战略目标胜过具体项目的效益 三.内置的 ...
- FineReport:任意时刻只允许在一个客户端登陆账号的插件
在使用FineReport报表系统中,处于账户安全考虑,有些企业希望同一账号在任意时刻智能在统一客户端登录.那么当A用户在C1客户端登陆后,该账号又在另外一个C2客户端登陆,服务器如何取判断呢? 开发 ...
- NOIP模板整理计划
先占个坑 [update]noip结束了,弃了 一.图论 1.单源最短路 洛谷P3371 (1)spfa 已加SLF优化 #include <iostream> #include < ...
- 解决托管在Windows上的Stash的Pull request无法合并的问题
最近尝试合并一个托管在Windows的Stash系统中的pull request时,发现合并按钮被禁用,显示有冲突不能合并,但是在diff页面中没有现实冲突,而且代码实际上并没有任何冲突. 后来在这篇 ...