解析大型.NET ERP系統 設計通用Microsoft Excel導入功能

作企業管理軟件很難避免與Microsoft Excel打交道,經常是軟件作好了,客戶要求說再作一個Excel導入功能。導入Excel數據的功能的難度不大,從Excel列數據欄位的取值,驗證值,再導入到數據庫表中。然而一直是在作重複工做,寫過不可勝數的Excel導入程序,每次只是知足於問題解決,後來終於找到一個方法,實現通用的Excel數據導入。html

設計通用的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的表頭,它包含字段定義,字段前面有加表,這樣可支持主從表導入。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的每行數據之間的關係。

目前尚未實現導入三層表數據。

相關文章
相關標籤/搜索