作企業管理軟件很難避免與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的每行數據之間的關係。
目前尚未實現導入三層表數據。