本教程主要說明若是使用Magicodes.IE.Excel完成學生數據的Excel導入。git
在本篇教程中,咱們僅演示使用Excel來完成學生數據的導入。咱們須要在已準備好的工程中安裝如下包,參考命令以下所示:github
Install-Package Magicodes.IE.Excel
主要代碼以下所示:shell
學生數據Dtoapp
/// <summary> /// 導入學生數據Dto /// IsLabelingError:是否標註數據錯誤 /// </summary> [ExcelImporter(IsLabelingError = true)] public class ImportStudentDto { /// <summary> /// 序號 /// </summary> [ImporterHeader(Name = "序號")] public long SerialNumber { get; set; } /// <summary> /// 學籍號 /// </summary> [ImporterHeader(Name = "學籍號")] [MaxLength(30, ErrorMessage = "學籍號字數超出最大限制,請修改!")] public string StudentCode { get; set; } /// <summary> /// 姓名 /// </summary> [ImporterHeader(Name = "姓名")] [Required(ErrorMessage = "學生姓名不能爲空")] [MaxLength(50, ErrorMessage = "名稱字數超出最大限制,請修改!")] public string Name { get; set; } /// <summary> /// 身份證號碼 /// </summary> [ImporterHeader(Name = "身份證號", IsAllowRepeat = false)] [Required(ErrorMessage = "身份證號不能爲空")] [MaxLength(18, ErrorMessage = "身份證字數超出最大限制,請修改!")] public string IdCard { get; set; } /// <summary> /// 性別 /// </summary> [ImporterHeader(Name = "性別")] [Required(ErrorMessage = "性別不能爲空")] [ValueMapping("男", 0)] [ValueMapping("女", 1)] public Genders Gender { get; set; } /// <summary> /// 家庭地址 /// </summary> [ImporterHeader(Name = "家庭住址")] [Required(ErrorMessage = "家庭地址不能爲空")] [MaxLength(200, ErrorMessage = "家庭地址字數超出最大限制,請修改!")] public string Address { get; set; } /// <summary> /// 家長姓名 /// </summary> [ImporterHeader(Name = "家長姓名")] [Required(ErrorMessage = "家長姓名不能爲空")] [MaxLength(50, ErrorMessage = "家長姓名數超出最大限制,請修改!")] public string Guardian { get; set; } /// <summary> /// 家長聯繫電話 /// </summary> [ImporterHeader(Name = "家長聯繫電話")] [MaxLength(20, ErrorMessage = "家長聯繫電話字數超出最大限制,請修改!")] public string GuardianPhone { get; set; } /// <summary> /// 學號 /// </summary> [ImporterHeader(Name = "學號")] [MaxLength(30, ErrorMessage = "學號字數超出最大限制,請修改!")] public string StudentNub { get; set; } /// <summary> /// 宿舍號 /// </summary> [ImporterHeader(Name = "宿舍號")] [MaxLength(20, ErrorMessage = "宿舍號字數超出最大限制,請修改!")] public string DormitoryNo { get; set; } /// <summary> /// QQ /// </summary> [ImporterHeader(Name = "QQ號")] [MaxLength(30, ErrorMessage = "QQ號字數超出最大限制,請修改!")] public string QQ { get; set; } /// <summary> /// 民族 /// </summary> [ImporterHeader(Name = "民族")] [MaxLength(2, ErrorMessage = "民族字數超出最大限制,請修改!")] public string Nation { get; set; } /// <summary> /// 戶口性質 /// </summary> [ImporterHeader(Name = "戶口性質")] [MaxLength(10, ErrorMessage = "戶口性質字數超出最大限制,請修改!")] public string HouseholdType { get; set; } /// <summary> /// 聯繫電話 /// </summary> [ImporterHeader(Name = "學生聯繫電話")] [MaxLength(20, ErrorMessage = "手機號碼字數超出最大限制,請修改!")] public string Phone { get; set; } /// <summary> /// 狀態 /// 測試可爲空的枚舉類型 /// </summary> [ImporterHeader(Name = "狀態")] public StudentStatus? Status { get; set; } /// <summary> /// 備註 /// </summary> [ImporterHeader(Name = "備註")] [MaxLength(200, ErrorMessage = "備註字數超出最大限制,請修改!")] public string Remark { get; set; } /// <summary> /// 是否住校(宿舍) /// </summary> [ImporterHeader(IsIgnore = true)] public bool? IsBoarding { get; set; } /// <summary> /// 所屬班級id /// </summary> [ImporterHeader(IsIgnore = true)] public Guid ClassId { get; set; } /// <summary> /// 學校Id /// </summary> [ImporterHeader(IsIgnore = true)] public Guid? SchoolId { get; set; } /// <summary> /// 校區Id /// </summary> [ImporterHeader(IsIgnore = true)] public Guid? CampusId { get; set; } /// <summary> /// 專業Id /// </summary> [ImporterHeader(IsIgnore = true)] public Guid? MajorsId { get; set; } /// <summary> /// 年級Id /// </summary> [ImporterHeader(IsIgnore = true)] public Guid? GradeId { get; set; } }
如上述代碼所示,咱們定義了以上學生數據Dto,主要注意事項以下:async
性別枚舉單元測試
定義以下所示:測試
/// <summary> /// 性別 /// </summary> public enum Genders { /// <summary> /// 男 /// </summary> Man = 0, /// <summary> /// 女 /// </summary> Female = 1 }
注意上文中的第7點。ui
/// <summary> /// 學生狀態 正常、流失、休學、勤工儉學、頂崗實習、畢業、參軍 /// </summary> public enum StudentStatus { /// <summary> /// 正常 /// </summary> [Display(Name = "正常")] Normal = 0, /// <summary> /// 流失 /// </summary> [Description("流水")] PupilsAway = 1, /// <summary> /// 休學 /// </summary> [Display(Name = "休學")] Suspension = 2, /// <summary> /// 勤工儉學 /// </summary> [Display(Name = "勤工儉學")] WorkStudy = 3, /// <summary> /// 頂崗實習 /// </summary> [Display(Name = "頂崗實習")] PostPractice = 4, /// <summary> /// 畢業 /// </summary> [Display(Name = "畢業")] Graduation = 5, /// <summary> /// 參軍 /// </summary> [Display(Name = "參軍")] JoinTheArmy = 6 }
注意上文中的第7點。spa
導入以前是否是得準備一份模板?對於咱們,手寫模板?這是不存在的。Magicodes.IE.Excel封裝了根據DTO自動生成Excel導入模板的方法,咱們能夠直接調用。這裏咱們來看下導入的相關方法:3d
/// <summary> /// 導入 /// </summary> public interface IImporter { /// <summary> /// 生成Excel導入模板 /// </summary> /// <typeparam name="T"></typeparam> /// <returns></returns> Task<TemplateFileInfo> GenerateTemplate<T>(string fileName) where T : class, new(); /// <summary> /// 生成Excel導入模板 /// </summary> /// <typeparam name="T"></typeparam> /// <returns>二進制字節</returns> Task<byte[]> GenerateTemplateBytes<T>() where T : class, new(); /// <summary> /// 導入模型驗證數據 /// </summary> /// <typeparam name="T"></typeparam> /// <param name="filePath"></param> /// <returns></returns> Task<ImportResult<T>> Import<T>(string filePath) where T : class, new(); }
經過以上方法中的GenerateTemplate,咱們能夠獲得須要的導入模板。具體使用能夠參考如下單元測試:
public IImporter Importer = new ExcelImporter(); [Fact(DisplayName = "生成學生數據導入模板(測試枚舉生成模板)")] public async Task GenerateStudentImportTemplate_Test() { var filePath = Path.Combine(Directory.GetCurrentDirectory(), nameof(GenerateStudentImportTemplate_Test) + ".xlsx"); if (File.Exists(filePath)) File.Delete(filePath); var result = await Importer.GenerateTemplate<ImportStudentDto>(filePath); result.ShouldNotBeNull(); File.Exists(filePath).ShouldBeTrue(); //TODO:讀取Excel檢查表頭和格式 }
以上DTO獲取模板並填充數據後以下圖所示:
注意:枚舉會自動生成下拉選擇,必填項列頭會標紅。
根據模板填充數據後,咱們就能夠進行數據導入了。一般狀況下,咱們有如下步驟:
驗證導入數據
經過Magicodes.IE.Excel導入數據會自動進行驗證,而且輸出驗證結果,以便於前臺顯示。具體咱們能夠經過其導入的結果類來了解:
/// <summary> /// 導入結果 /// </summary> public class ImportResult<T> where T : class { /// <summary> /// </summary> public ImportResult() { RowErrors = new List<DataRowErrorInfo>(); } /// <summary> /// 導入數據 /// </summary> public virtual ICollection<T> Data { get; set; } /// <summary> /// 驗證錯誤 /// </summary> public virtual IList<DataRowErrorInfo> RowErrors { get; set; } /// <summary> /// 模板錯誤 /// </summary> public virtual IList<TemplateErrorInfo> TemplateErrors { get; set; } /// <summary> /// 導入異常信息 /// </summary> public virtual Exception Exception { get; set; } /// <summary> /// 是否存在導入錯誤 /// </summary> public virtual bool HasError => Exception != null || (TemplateErrors?.Count(p => p.ErrorLevel == ErrorLevels.Error) ?? 0) > 0 || (RowErrors?.Count ?? 0) > 0; }
其中,
Data爲數據結果
RowErrors爲驗證錯誤,好比必填、重複驗證、文本長度等等。會給出行號、字段以及字段錯誤集合
TemplateErrors爲模板錯誤,好比必填列缺失等錯誤信息。支持錯誤等級(警告、錯誤)
Exception爲導入異常信息
HasError爲是否存在錯誤(不包含警告)
經過ImportResult,咱們就能夠很方便的拿到導入驗證錯誤而無須額外編寫代碼。一般在導入時咱們須要判斷HasError屬性並給前臺返回具體的錯誤結果。
數據導入參考代碼以下所示:
[Fact(DisplayName = "學生基礎數據導入")] public async Task StudentInfoImporter_Test() { var filePath = Path.Combine(Directory.GetCurrentDirectory(), "TestFiles", "Import", "學生基礎數據導入.xlsx"); var import = await Importer.Import<ImportStudentDto>(filePath); import.ShouldNotBeNull(); if (import.Exception != null) _testOutputHelper.WriteLine(import.Exception.ToString()); if (import.RowErrors.Count > 0) _testOutputHelper.WriteLine(JsonConvert.SerializeObject(import.RowErrors)); import.HasError.ShouldBeFalse(); import.Data.ShouldNotBeNull(); import.Data.Count.ShouldBe(16); }
客戶說雖然你提示了,可是我仍是不知道哪裏錯了!!怎麼辦?!!
咱們貼心的爲你準備了導入數據的Excel文件的標註:
如何開啓這個【史詩劇情】呢?僅需:
[ExcelImporter(IsLabelingError = true)]
開啓後,咱們將自動保存「{目標文件名稱}_.xlsx」的標註文件到目標位置。
沒有錯誤了?也就是HasError爲false,那麼咱們就能夠直接拿到Data隨心所欲了!
整個學生數據的導入教程就此結束了。相關庫會一直更新,在功能體驗上有可能會和本文教程有細微的出入,請以相關具體代碼、版本日誌、單元測試示例爲準。