Demo源碼
背景
通過程序將excel導入到數據庫中是一項非常常見的功能。通常的做法是:先將excel轉成DataTable,然后將DataTable轉換成List<T>,最終通過List<T>導入進數據庫。
同時,一般的ExcelUtil基類也會提供類似List<T> GetEntityListFromFile<T>(string fileName)的實現,但是這些實現一般都是機械化地對應,缺少一些自定義的操作。
問題
在我的開發過程中,就導入excel這一塊就碰到了以下的一些問題:
以上這些問題,僅僅通過基類提供的方法是無法實現的,所以本篇文章提供一種高度自定義的Excel導入通過模塊的實現,期以解決以上問題。
Demo程序結構概覽
ps:要下班了,今日就先發這么多,
大家可以先下Demo看一下,功能都實現了,有問題可以大家一起交流,
如果大家想知道具體流程,我就再添加。
實現思路
首先,需要明確的是我們的需求:
接下來,就簡要講述一下以上功能的實現:
/// <summary> /// 高度可擴展的excel導入 By Dean 20140320 /// 應用場景:1 需要支持實體類屬性和excel中列的一對多關系 如excel中的列名是JHB、聚好幣、PV時候,均認為映射到實體中的JHB字段 ///2 需要支持實體類屬性和excel中列的多對一關系 如excel中只包含“名稱”列,有同時填充實體類的Code & Name屬性時,可以將Code屬性也對應到“名稱”列,然后寫一個轉換函數,通過“名稱”從DB中取出Code再映射 /// 功 能:1 可以自動剔除全部為空的行 /// 2 能夠自定義地設置將excel中的列映射到實體類上的哪個字段,以及映射的方法 /// 3 能夠對excel中的數據的有效性進行自定義的檢查 /// </summary> /// <typeparam name="Entity"></typeparam> public class ImportUtil<Entity> where Entity : new()
public ImportUtil(Dictionary<string, string> allColumns) { AllColumns = allColumns; }
//實體類列和excel列的對應關系 Dictionary<string, string> allColumns = new Dictionary<string, string> { {"ID","編號"}, {"StudentID","學生編號|學生ID"},{"StudentName","學生編號|學生ID"}, {"Disc該構造函數傳入參數allColumns,是一個Dictionary<string,string>類型的,該參數實現了需求2,字典的Key是實體類Entity中的【屬性名稱】,字典的Value是excel中的【列名稱】,使用|來支持excel的多列名。
- ImportUtil類中有唯一的對外公開的方法【public List<Entity> GetEntityList】
/// <summary> /// 根據excel文件名獲取實體類列表 《唯一向外部公開的接口》 /// </summary> /// <param name="fileName">excel文件名</param> /// <param name="errorInfo">導入過程中的任何錯誤信息都會放到這里面</param> /// <param name="converterFields">需要進行預定義類型轉換的列</param> /// <param name="customConverts">需要進行自定義類型轉換(key是實體類對應的列,value是包含excel中對應列的值和操作后的返回值的Func)</param> /// <param name="dataValidateChecks">在進行excel列映射到實體類之前,對excel列中的值進行的預檢查</param> /// <returns>實體類列表</returns> public List<Entity> GetEntityList(string fileName, List<string> errorInfo, Dictionary<KnownDataType, List<string>> converterFields = null, Dictionary<string, Func<object, object>> customConverts = null, Dictionary<string, Func<object, string>> dataValidateChecks = null)該方法有5個輸入參數,其中fileName和errorInfo是必輸的,方法最終返回的就是我們所需要的List<Entity>,方法的執行過程就是先通過excel的地址將excel導入稱為DataTable,然后將DataTable轉換成List<T>,在轉換的過程中進行數據的有效性驗證和數據值的類型轉換。
下面簡單介紹一下這5個參數:
- fileName,string,需要導入的excel的地址;
- errorInfo,List<string>,導入過程中所發生的錯誤信息;
- convertFields,Dictionary<KnownDataType,List<string>>,預定義的類型轉換;excel中的列都是object類型的,而Entity中的屬性卻是強類型的,對于Int,Decimal,Double,DateTime已經定義好了相關的轉換函數,僅需將Entity屬性名稱傳入,在進行DataTable轉List<Entity>時就能夠將對應Column的值進行預定義的類型轉換
//預定義類型轉換 Dictionary<KnownDataType, List<string>> convertFields = new Dictionary<KnownDataType, List<string>> { {KnownDataType.Int, new List<string> {"ID", "StudentID", "DisciplineID"}}, {KnownDataType.Double, new List<string> {"Score"}} };- customConverts,Dictionary<string,Func<object,object>>,自定義的類型轉換;預定義的類型轉換通常只是將excel中的列轉成對應的類型或者給個默認值,是通用的操作,但是我們常常需要對excel中的列進行自定義的轉換,例如:excel中有“編號”列,設置同時對應到Entity的“ID”、“Name”屬性,而“ID”屬性可以直接使用預定義轉換完成,“Name”列則需要通過“編號”從數據庫中找到“Name”再賦值給“Name”。因此,這時候我們需要自定義的轉換。寫法如下:
//自定義類型轉換 Dictionary<string, Func<object, object>> customConverts = new Dictionary<string, Func<object, object>> { { "StudentName", currColumn => { int studentID; if (currColumn != null && int.TryParse(currColumn.ToString(), out studentID)) { var r = DataPool.EntireStudents.Find(c => c.ID == studentID); if (r != null) { return r.Name; } } return string.Empty; } }, { "MakeUpExamTime", currColumn => { DateTime colDateTime; if (currColumn != null && DateTime.TryParse(currColumn.ToString(), out colDateTime)) { return colDateTime; } return null; } } };- dataValidateChecks,Dictionary<string,Func<object,string>>,excel列的數據有效性驗證,在Entity的每個屬性的賦值之前都會先驗證一下excel的數據是否有效,Key是要驗證的屬性的名字,Value是一個Func,輸入參數就是excel的列值,返回的是string,驗證通過時是string.Empty,驗證不通過返回的是錯誤信息。寫法如下:
//excel列的數據有效性驗證 以下完成了對excel中編號列的值必須為整數且不為空的驗證的設定 Dictionary<string,Func<object,string>> dataValidateChecks = new Dictionary<string, Func<object, string>> { { "ID", currColumn => { int idInt; if (currColumn!=null&&int.TryParse(currColumn.ToString(),out idInt)) { return string.Empty; } return "ID不能為空且必須為整數"; } } };//執行excel導入 var res = importUtil.GetEntityList(excelPath, errors, convertFields, customConverts, dataValidateChecks);總結
以上就完成了一個excel的自定義導入的功能,謝謝。
Demo源碼
新聞熱點
疑難解答