本教程主要说明如果使用Magicodes.IE.Excel完成学生数据的Excel导入。
要点
主要步骤
1.安装包Magicodes.IE.Excel
在本篇教程中,我们仅演示使用Excel来完成学生数据的导入。我们需要在已准备好的工程中安装以下包,参考命令如下所示:
Install-Package Magicodes.IE.Excel
主要代码如下所示:
/// <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,主要注意事项如下:
定义如下所示:
/// <summary>
/// 性别
/// </summary>
public enum Genders
{
/// <summary>
/// 男
/// </summary>
Man = 0,
/// <summary>
/// 女
/// </summary>
Female = 1
}
注意上文中的第7点。
///// <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点。
导入之前是不是得准备一份模板?对于我们,手写模板?这是不存在的。Magicodes.IE.Excel封装了根据DTO自动生成Excel导入模板的方法,我们可以直接调用。这里我们来看下导入的相关方法:
/// <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获取模板并填充数据后如下图所示:
Excel导入模板
注意:枚举会自动生成下拉选择,必填项列头会标红。
根据模板填充数据后,我们就可以进行数据导入了。通常情况下,我们有以下步骤:
通过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;
}
其中,
客户说虽然你提示了,但是我还是不知道哪里错了!!怎么办?!!
我们贴心的为你准备了导入数据的Excel文件的标注:
数据错误标注
多个错误
如何开启这个【史诗剧情】呢?仅需:
[ExcelImporter(IsLabelingError = true)]
开启后,我们将自动保存“{目标文件名称}_.xlsx”的标注文件到目标位置。
没有错误了?也就是HasError为false,那么我们就可以直接拿到Data为所欲为了!
整个学生数据的导入教程就此结束了。相关库会一直更新,在功能体验上有可能会和本文教程有细微的出入,请以相关具体代码、版本日志、单元测试示例为准。
转载是一种动力 分享是一种美德