数据验证是每个项目必须存在的,可以防止不符合系统规范的数据进入系统进而导致系统不稳定甚至崩溃。我们可以自己编写代码进行验证,但是这样一方面代码量较大,另一方面有可能验证代码覆盖不完全。但是在 Entity Framework Core (以下简称 EF Core )中这些问题全可以解决。

作者:朱钢

数据验证是每个项目必须存在的,可以防止不符合系统规范的数据进入系统进而导致系统不稳定甚至崩溃。我们可以自己编写代码(包括前台和后台代码)进行验证,但是这样一方面代码量较大,另一方面有可能验证代码覆盖不完全。但是在 Entity Framework Core (以下简称 EF Core )中这些问题全可以解决。在 EF Core 中有两种验证模式,分别是内置模型验证和第三方扩展模型验证。下面我分别对这两种模式进行讲解,在讲解前我们先来创建必须的模型。

public class User
{ public int Id { get; set; } public string Name { get; set; } public int Age { get; set; }
} 

一、内置模型验证

在 EF Core 中并没有 Fluent API 模式对数据进行验证,因此我们只能通过 Data Annotations (数据注解)方式来进行数据验证,也就是添加特性的方法来验证数据。例如我们要验证 User 模型中的 Name 的长度,Name 长度不能大于 5 ,我们只需在 Name 属性上增加 StringLength 数据注解即可, StringLength 位于命名空间 System.ComponentModel.DataAnnotations 中,修改 User 模型代码如下:

public class User
{ public int Id { get; set; } [StringLength(5)] public string Name { get; set; } public int Age { get; set; }
} 

上述代码通过 StringLength(5) 数据注解将 Name 属性的数据长度限定在 5 ,并且在数据提交时按照这个约定进行数据验证。下面我们就通过数据注解中的验证器来验证刚才添加的特性。首先我们要创建一个上下文的扩展方法:

public static List<ValidationResult> ExecuteValidation(DbContext context)
{ List<ValidationResult> result = new List<ValidationResult>(); var models = context.ChangeTracker.Entries() .Where(p => (p.State == EntityState.Added) || (p.State == EntityState.Modified)); foreach (var model in models) { var entity = model.Entity; var valProvider = new ValidationDbContextServiceProvider(context); var valContext = new ValidationContext(entity, valProvider, null); List<ValidationResult> error = new List<ValidationResult>(); if(!Validator.TryValidateObject(entity,valContext,error,true)) { result.AddRange(error); } return result.ToList(); }
} 

在上述代码中我们通过 ChangeTracker 方法找出被追踪的实体,然后过滤出需要添加和更新的实体,对这些实体进行数据验证。最后我们通过 Validator 中的 TryValidateObject 方法验证实体数据并返回校验错误信息。在业务代码中我们调用前面定义的 ExecuteValidation 方法进行验证,如果验证通过就调用 EF Core 的 SaveChange() 方法,如果未通过就调用相应的处理代码,代码片段如下:

if(context.ExecuteValidation().Any())
{ foreach(var error in context.ExecuteValidation()) { //处理代码 }
}
else
{ context.SaveChange();
} 

讲到这里估计会有很多小伙伴说每个业务代码中都要这么写太麻烦了,而且也产生了大量的重复代码。那么重复代码这个问题该怎么解决呢?这时一定有部分小伙伴想到了通过重写 SaveChanges 方法,将验证代码加入到这个方法中,这样就可以解决刚才的那个问题,达到一劳永逸的效果。具体代码如下:

public override int SaveChanges(bool acceptAllChangesOnSucces)
{ var provider = ((IInfrastructure<IServiceProvider>)this).Instance; var items = new Dictionary<object, object>(); var models = this.ChangeTracker.Entries() .Where( p => (p.State == EntityState.Added)||(p.State==EntityState.Modified)); foreach (var model in models) { var entity = model.Entity; var context = new ValidationContext(entity, provider, items); List<ValidationResult> results = new List<ValidationResult>(); if(!Validator.TryValidateObject(entity,context,results,true)) { foreach (var result in results) { if(result!=ValidationResult.Success) { throw new ValidationException(result.ErrorMessage); } } } } return base.SaveChanges();
} 

通过上述代码就可以一处编写验证,多处使用了。具体的思路和前面所讲的一样,这里就不再进行讲解了。

二、第三方扩展模型验证

前面所讲的是通过数据注解的方式来进行数据验证的,但是如果是使用 Fluent API 的方式就没办法解决文章开头所说的问题,因为Fluent API 模式并没有提供对数据模型的验证。这时我们可以使用第三方扩展,在 EF Core 中常用的模型数据验证第三方扩展是 FluentValidation.AspNetCore 。在使用前我们需要在 NuGet 中下载此扩展。 FluentValidation.AspNetCore 安装完成后我们需要为模型创建验证器,验证器是一个继承自 AbstractValidator<T> 的类,验证规则使用 RuleFor 方法定义在验证器构造函数中。代码如下:

public class ModelValidator:AbstractValidator<User>
{ public ModelValidator() { RuleFor(p => p.Name).NotEmpty().WithMessage("姓名不能为空"); RuleFor(p => p.Name).MaximumLength(5).WithMessage("姓名长度在5字节"); }
} 

上述代码进行了两个验证,一个是验证 Name 字段是否为空,另一个是验证 Name 字段的长度,其中我们通过 MaximumLength 规定了 Name 字段的最长长度为 5 字节。之后我们通过 WithMessage 方法返回我们自定义的错误信息。 我们定义完验证规则后下一步就是将我们定义的验证规则与应用程序连接起来,这里我们需要用到 AddFluentValidation 来注入,例如在 Asp.Net Core 程序中我们将注入程序写入 Startup 的 ConfigureServices 方法里。我们调用 AddFluentValidation 方法会将 FluentValidation 服务添加到 Asp.Net Core 中,然后使用 RegisterValidatorsFromAssembly 方法将自定义的验证代码注入到容器中,代码段如下:

public void ConfigureServices(IServiceCollection services)
{ services.AddMvc() .AddFluentValidation(p=> p.RegisterValidatorsFromAssemblyContaining<Startup>());
} 

在需要验证数据的地方我们通过 ModelState 获取验证状态,验证通过就执行后续代码,不通过就执行处理代码。示例代码如下:

if(ModelState.IsValid)
{ //后续代码
}
else
{ //验证不通过处理代码
} 

这里有一点需要注意,当传递的实体为 null 时,将返回错误信息,这是因为 AbstractValidator 中存在 EnsureInstanceNotNull 方法,这个方法在实例为 null 时会抛出异常,即使重写该方法也无法返回自定义的错误信息。如果需要验证实体集合就需要使用 RuleForEach 方法即可,对于自定义验证规则则可使用 SetValidator 方法。

三、总结

本篇文章讲解了 EF Core 数据验证的方法,虽然讲的是 EF Core 的方法,但是同样也适用于 EF6 ,这些内容是常用的,上述部分代码可以在大部分项目中通用。

阅读目录(置顶)(长期更新计算机领域知识)

阅读目录(置顶)(长期更新计算机领域知识)

阅读目录(置顶)(长期科技领域知识)

歌谣带你看java面试题

第一百五十二期:白话Entity Framework Core数据验证相关推荐

  1. ASP.NET Core 入门教程 8、ASP.NET Core + Entity Framework Core 数据访问入门

    ASP.NET Core 入门教程 8.ASP.NET Core + Entity Framework Core 数据访问入门 原文:ASP.NET Core 入门教程 8.ASP.NET Core ...

  2. 第一百五十一期:最新计算机技能需求排名出炉:Python仅排第三,第一你猜得到吗?

    除了编程语言之外,要想找一份计算机相关的工作,还需要很多其他方面的技能.最近,来自美国求职公司 Indeed 的一份报告显示:在全美工作技能需求中,数据库语言 SQL.编程语言 Java 分列前两位. ...

  3. 第一百五十期:Java程序员必备:异常的十个关键知识点

    总结了Java异常十个关键知识点,面试或者工作中都有用哦,加油.异常是指阻止当前方法或作用域继续执行的问题.比如你读取的文件不存在,数组越界,进行除法时,除数为0等都会导致异常.  前言 总结了Jav ...

  4. 第一卷清晨的帝国第一百五十五章杀破道

    刚刚走进山腰的云雾中,宁缺便听到身后传来片骤如雨的马蹄声! 这些年来一直深藏在他内心深处的恐惧回忆,随着这些熟悉的马蹄声骤然复苏,然后不可抑止的泛滥开来,瞬间占据了他的全部身躯,令他的身体变得无比僵硬 ...

  5. leecode第一百五十五题(最小栈)

    class MinStack { public:stack<int> cur_stack;stack<int> cur_min;//用来存储最小值的栈int min_num;M ...

  6. 第一百五十三期: 云迁移可能失败的5种方式以及成功的5种方式

    通过将应用程序迁移到云平台中,企业可以提高安全性.数据访问.可扩展性和IT灵活性.将业务迁移到云平台还可以为企业节省成本.以下是导致企业云迁移失败的五个主要原因以及其解决方法. 作者:Andy Pat ...

  7. 第一百三十二期:MySQL系列:一句SQL,MySQL是怎么工作的?

    当我们在mysql窗口或者数据库连接工具中输入一句sql后,我们就可以获取到想要的数据,这中间MySQL到底是怎么工作的呢? 作者:Java架构学习交流 对于MySQL而言,其实分为客户端与服务端. ...

  8. 第一百二十二期:大数据分析:红包先抢好,还是后抢好

    本文用matlab程序,模拟微信给10个人发红包,设定次数1亿次,统计每个人抢到的红包,最佳手气和最差手气次数,用以分析红包是应该先抢还是后抢? 作者:景因分析 本文用matlab程序,模拟微信给10 ...

  9. 第一百五十天 how can I坚持

    今天生日,好多第一次. 第一次QQ上有那么多好友给说生日快乐. 第一次,去欢乐谷玩,第一次坐过山车,第一次坐太阳神车. 第一次看舞台剧-金面王朝,场景好真实,洪水.. 可惜只是自己一个人,玩的一点也不 ...

最新文章

  1. vue组件父子组件之间传递数据
  2. 【Mysql】_1在centos7虚拟机上完成Mysql环境部署
  3. java源文件编译成jar_从源文件和JAR文件构建Java代码模型
  4. 数据结构 二叉树面试笔试编程题集
  5. [Axis2与Eclipse整合开发Web Service系列之二] Top-Down方式,通过WSDL逆向生成服务端(续)
  6. 硅谷对“元宇宙”一无所知
  7. VB 子类化技术详解
  8. 如何让语音芯片与功放芯片之间更好的配合,使得产品音效更好
  9. 等压线上怎么画风向_如何利用等压线图判定天气
  10. python实现免费同声传译 (离线语音识别+免费翻译接口+系统声音录制)
  11. 【论文阅读】自动作文评分系统:一份系统的文献综述
  12. ubuntu 19.04源
  13. 功能测试与性能测试常见方法
  14. 偏振器件传输矩阵matlab编程,关于传输矩阵法模拟光子晶体的MATLAB编程
  15. 三星android5.0 蓝牙,蓝牙5.0手机有哪些 蓝牙5.0和4.2的区别是什么【区别介绍】
  16. 黑马程序员--银行以及交通系统项目个人理解
  17. Java各种运算符号的含义及区别汇总
  18. AFM测试常见问题及解答(二)
  19. 【Introduction to Artificial Intelligence and Data Analytics】(TBC)
  20. 2022-2028全球可观察性解决方案套件软件行业调研及趋势分析报告

热门文章

  1. 互联网日志的种类、存储和计算
  2. python快速检测视频跳过帧_使用Python实现跳帧截取视频帧
  3. 万兆网卡实际吞吐量_AKITIO 10G/NBASE-T PCIe 网卡开箱拆解评测
  4. 【 Grey Hack 】万金油脚本:常见端口获取Password
  5. 实例讲解getopt()函数的使用
  6. Linux 系统应用编程——出错处理(errno)
  7. 将windows下编辑好的文件(GBK)转换成Linux下的格式(UTF8)
  8. 前端学习(3224):字符串形式
  9. 前端学习(3050):vue+element今日头条管理-表格组件基本使用
  10. 前端学习(3018):vue+element今日头条管理--反馈