Magicodes.IE之导入学生数据教程

基础教程之导入学生数据

说明

本教程主要说明如果使用Magicodes.IE.Excel完成学生数据的Excel导入。

要点

  • 本教程使用Magicodes.IE.Excel来完成Excel数据导入

  • 需要通过创建Dto来完成导入

  • Magicodes.IE.Excel可以根据Dto以及特性设置来自动生成导入的Excel模板,数据验证(包括重复验证),模板验证,读取设置,值约束和映射,输出Excel验证标注

主要步骤

1.安装包Magicodes.IE.Excel

在本篇教程中,我们仅演示使用Excel来完成学生数据的导入。我们需要在已准备好的工程中安装以下包,参考命令如下所示:

Install-Package Magicodes.IE.Excel

2.创建导入Dto

主要代码如下所示:

  • 学生数据Dto

/// <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,主要注意事项如下:

    • ExcelImporter特性可以设置一些导入的全局设置,比如是否标注错误、导入Sheet名称(如不设置则自动获取第一个)、截止读取的列数、表头位置。

    • 支持常用的数据验证设置,比如必填、最大长度。

    • 支持数据重复校验,比如身份证号码。见ImporterHeader特性的IsAllowRepeat设置。

    • 支持列头设置,将ImporterHeader的Name属性。除此之外,ImporterHeader还支持自动过滤空格(默认启用)、处理掉所有的空格、列索引等。

    • 对数据列启用了忽略设置,见SchoolId的”[ImporterHeader(IsIgnore = true)]”。

    • 使用了值映射,见“Gender”属性。启用值映射之后,将不会从枚举定义中获取值映射。

    • 支持枚举,支持从枚举的Display、Description特性中获取值映射。枚举定义见下文。

  • 性别枚举

定义如下所示:

/// <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点。

3.生成导入模板并填充数据

导入之前是不是得准备一份模板?对于我们,手写模板?这是不存在的。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导入模板

注意:枚举会自动生成下拉选择,必填项列头会标红。

4.获取学生导入验证错误和数据

根据模板填充数据后,我们就可以进行数据导入了。通常情况下,我们有以下步骤:

  • 验证导入数据

通过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为所欲为了!

最后

整个学生数据的导入教程就此结束了。相关库会一直更新,在功能体验上有可能会和本文教程有细微的出入,请以相关具体代码、版本日志、单元测试示例为准。

转载是一种动力 分享是一种美德

如果喜欢作者的文章,请关注【麦扣聊技术】订阅号以便第一时间获得最新内容。本文版权归作者和湖南心莱信息科技有限公司共有,欢迎转载,但未经作者同意必须保留此段声明,且在文章页面明显位置给出原文连接,否则保留追究法律责任的权利。

文档官网:docs.xin-lai.com

QQ群:

编程交流群<85318032> 

产品交流群<897857351>

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/312851.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

IP地址分类详解

一、IP地址简介 IP&#xff0c;即网际协议&#xff08;Internet Protocol&#xff09;&#xff0c;或称互联网协议&#xff0c;是用于报文交换网络的一种面向数据的协议。 IP是在TCP/IP协议中网络层的主要协议&#xff0c;任务是仅仅根据源主机和目的主机的地址传送数据。为此目…

[ASP.NET Core 3框架揭秘] 文件系统[1]:抽象的“文件系统”

ASP.NET Core应用 具有很多读取文件的场景&#xff0c;比如配置文件、静态Web资源文件&#xff08;比如CSS、JavaScript和图片文件等&#xff09;以及MVC应用的View文件&#xff0c;甚至是直接编译到程序集中的内嵌资源文件。这些文件的读取都需要使用到一个IFileProvider对象。…

[原]调试PInvoke导致的内存破坏

缘起 最近项目中遇到一个诡异的问题&#xff0c;程序在升级到.net4.6.1后&#xff0c;执行某个功能时会崩溃&#xff0c;提示访问只读内存区。大概规律如下:debug版不崩溃&#xff0c;release版稳定崩溃。只有x64位的程序崩溃&#xff0c;32位及anycpu编译出来的程序运行不会崩…

被忽略的TraceId,可以用起来了

前言.NetCore日志&#xff0c;相信大家多少都接触过&#xff0c;博客园有关 ① AspNetCore依赖注入第三方日志组件 ②第三方日志组件Nlog,Serilog 应用方法的博文层出不穷。结合程序的部署结构&#xff0c;本文分单体和微服务聊一聊AspNetCore中追踪日志流的方法。TraceIdAsp…

TCP协议详解

一、TCP协议简介 TCP协议&#xff0c;即传输控制协议&#xff08;Transmission Control Protocol&#xff09;&#xff0c;是一种面向连接的、可靠的、基于字节流的传输层通信协议。在因特网协议族中&#xff0c;TCP层是位于IP层之上&#xff0c;应用层之下的中间层。尽管IP层只…

UDP协议详解

一、UDP协议简介 UDP协议&#xff0c;即用户数据报协议&#xff08;User Datagram Protocol&#xff09;&#xff0c;是一个简单的面向数据报的传输层协议。UDP协议只在IP数据报服务商增加了很少一点的功能&#xff0c;就是复用和分用&#xff0c;以及差错检测的功能。 二、UDP…

冰雪奇缘,白色世界:四个IT人的四姑娘山双桥沟游记

去年9月初去了川西的稻城亚丁&#xff0c;体会了金色世界秋日童话&#xff0c;还写了一篇游记《从你的全世界路过-一群程序员的稻城亚丁游记》&#xff0c;也是得到了很多朋友和童鞋的点赞。今年11月初趁着周末的两天时间和朋友去了川西的四姑娘山&#xff0c;体会了白色世界冰…

TCP三次握手建立连接

一、三次握手的过程 TCP需要三次握手才能建立连接&#xff0c;整个过程如下图所示&#xff1a; 假设A运行的是TCP客户端进程&#xff0c;而B运行的是TCP服务端进程。最开始的时候两端的TCP进程都处于ClOSED&#xff08;关闭&#xff09;状态。 这时候&#xff0c;A主动打开连接…

[原]排错实战——通过对比分析sysinternals事件修复程序功能异常

缘起 最近&#xff0c;我们程序的某个功能在一台机器上不正常&#xff0c;但是在另外一台机器上却是正常的。代码是同一份&#xff0c;vs版本也一样&#xff08;打的补丁也一样&#xff09;。编译出来的程序在两台电脑上运行的结果就是不一样。惊不惊喜&#xff0c;意不意外&am…

[原]windbg调试系列——崩溃在ComFriendlyWaitMtaThreadProc

前言 这是几年前在项目中遇到的一个崩溃问题&#xff0c;崩溃在了ComFriendlyWaitMtaThreadProc()里。没有源码&#xff0c;耗费了我很大精力&#xff0c;最终通过反汇编并结合原代码才最终搞清楚了事情的来龙去脉。本文的分析是基于真实项目进行的&#xff0c;中间略去了很多反…

TCP四次握手释放连接

一、四次握手的过程 TCP需要三次握手才能建立连接&#xff0c;整个过程如下图所示&#xff1a; 假设A运行的是TCP客户端进程&#xff0c;而B运行的是TCP服务端进程。最开始的时候两端的TCP进程都处于ESTABLISHED&#xff08;已建立连接&#xff09;状态。 这时候&#xff0c;A…

开源WPF控件库MaterialDesignInXAML推荐

今天介绍一个开源的C# WPF开源控件库&#xff0c;非常漂亮&#xff0c;重点是开源哦WPF做桌面开发是很有优势的&#xff0c;除了微软自带的控件外&#xff0c;还有很多第三方的控件库&#xff0c;比如收费的Dev Express For WPF、Telerik For WPF等&#xff0c;及Github上开源免…

TCP连续ARQ协议和滑动窗口协议

TCP协议通过使用连续ARQ协议和滑动窗口协议&#xff0c;来保证数据传输的正确性&#xff0c;从而提供可靠的传输。 一、ARQ协议 ARQ协议&#xff0c;即自动重传请求&#xff08;Automatic Repeat-reQuest&#xff09;&#xff0c;是OSI模型中数据链路层和传输层的错误纠正协议之…

ASP.NET Core 集成测试中模拟登录用户的一种姿势

不管哪种用户验证方式&#xff0c;最终都是在验证成功后设置 HttpContext.User &#xff0c;后续处理环节通过 HttpContext.User 获取用户信息。如果能直接修改 HttpContext.User &#xff0c;就能达到模拟登录的目的&#xff0c;而 ASP.NET Core 的中间件&#xff08;middlewa…

【NServiceBus】什么是Saga,Saga能做什么

前言Saga单词翻译过来是指尤指古代挪威或冰岛讲述冒险经历和英雄业绩的长篇故事&#xff0c;对&#xff0c;这里强调长篇故事。许多系统都存在长时间运行的业务流程&#xff0c;NServiceBus使用基于事件驱动的体系结构将容错性和可伸缩性融入这些业务处理过程中。 当然…

数据一致性基本知识

在分布式系统中&#xff0c;我们经常提及CAP定理&#xff0c;即一致性&#xff08;Consistency&#xff09;、可用性&#xff08;Availability&#xff09;和分区容忍性&#xff08;Partition tolerance&#xff09;。在本文中&#xff0c;我们将对数据一致性这一知识进行基本回…

分享一次与SharpDX坑爹Bug刚正面的过程

和SharpDX坑爹的Variant刚正面几个月前我写了这篇文章《.NET中生成动态验证码》文章&#xff0c;其实里面藏着一个大坑。运行里面的代码&#xff0c;会发现运行的 gif图片并没有循环播放&#xff1a; 细心的网友也注意到了这个问题&#xff1a;……但后来他备注说“已解决”&am…

EF Core 3.0查询

随着.NET Core 3.0的发布&#xff0c;EF Core 3.0也随之正式发布&#xff0c;关于这一块最近一段时间也没太多去关注&#xff0c;陆续会去对比之前版本有什么变化没有&#xff0c;本节我们来看下两个查询。分组我们知道在EF Core 3.0版本之前&#xff0c;对于分组查询是在客户端…

经典排序算法(1)——冒泡排序算法详解

冒泡排序&#xff08;Bubble Sort&#xff09;是一种典型的交换排序算法&#xff0c;通过交换数据元素的位置进行排序。 一、算法基本思想 &#xff08;1&#xff09;基本思想 冒泡排序的基本思想就是&#xff1a;从无序序列头部开始&#xff0c;进行两两比较&#xff0c;根据…

C++模版和C#泛型求同存异录(一)sizeof(T)

sizeof(T)从C的模板代码往C#代码移植的时候发现了一个小问题。在C模板代码中 sizeof(T)是一种有效的写法&#xff0c;最终在会编译器展开成sizeof(int),sizeof(float)或者sizeof(myclass),然后在运行时这个代码是有效的&#xff0c;能够执行的。于是我们看上去就可以计算在运行…