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


    做企业管理软件很难避免与Microsoft Excel打交道,常常是软件做好了,客户要求说再做一个Excel导入功能。导入Excel数据的功能的难度不大,从Excel列数据栏位的取值,验证值,再导入到数据库表中。然而一直是在做重复工作,写过不计其数的Excel导入程序,每次只是满足于问题解决,后来终于找到一个方法,实现通用的Excel数据导入。

    设计通用的Excel导入功能,第一个实现要求是不能依赖Excel,客户的电脑或服务器很有可能没有安装Excel,所以微软的Office Interop一概不考虑。第二个实现要求是需要高度抽象化,也就是不依赖于具体的数据库表,这样实现了从具体表导入到通用表导入的抽象,可重复用的程度高。

    第一步是生成Excel模板文件,先看字段选择界面,传入一个数据库表,可枚举表的字段,供生成Excel模板文件:

    image

    这个功能的作用是生成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的每行数据之间的关系。

    目前还没有实现导入三层表数据。

     
  • 相关阅读:
    WCF后续之旅(3): WCF Service Mode Layer 的中枢—Dispatcher
    .Net 2.0对文件传输协议(FTP)操作(上传,下载,新建,删除,FTP间传送文件等)
    我的WCF之旅(13):创建基于MSMQ的Responsive Service
    .net程序集强名称签名实践
    WCF后续之旅(8):通过WCF Extension 实现与MS Enterprise Library Policy Injection Application Block 的集成
    .Net 2.0对文件传输协议(FTP)操作(上传,下载,新建,删除,FTP间传送文件等) 2
    WCF后续之旅(6): 通过WCF Extension实现Context信息的传递
    SilverlightCatchWcfError
    WCF后续之旅(7):通过WCF Extension实现和Enterprise Library Unity Container的集成
    WCF后续之旅(4):WCF Extension Point 概览
  • 原文地址:https://www.cnblogs.com/JamesLi2015/p/4700905.html
Copyright © 2020-2023  润新知