使用 C# 9 的records作为强类型ID - 初次使用
强类型ID
实体通常是整数,GUID或者string类型,因为数据库直接支持这些类型,但是,如果实体的ID的类型是一样的,比如都是整数的ID,这有可能会出现ID值传错的问题,看下边的示例。
public void AddProductToOrder(int orderId, int productId, int count)
{...
}...// 这个地方,参数传错了
AddProductToOrder(productId, orderId, int count);
上面的代码可以很好地通过检查并编译,但是在运行的时候就出问题了,这是逻辑bug。
幸运的是,可以定义强类型id来解决这个问题,这个想法很简单,为每个实体的ID声明一个特定的类型,现在需要这样写:
// 使用强类型ID代替整数ID
public void AddProductToOrder(OrderId orderId, ProductId productId, int count)
{...
}...// 这个地方,参数传错了
AddProductToOrder(productId, orderId, int count);
在上面的代码中,我们犯了与第一个示例相同的错误(交换productId和orderId),但是在这种情况下,类型不同,因此编译器会捕获该错误并报告错误,我们仍然需要对其进行修复,但是至少在生产中并没有爆炸。
编写一个强类型的id
public readonly struct ProductId : IEquatable<ProductId>
{public ProductId(int value){Value = value;}public int Value { get; }public bool Equals(ProductId other) => other.Value == Value;public override bool Equals(object obj) => obj is ProductId other && Equals(other);public override int GetHashCode() => Value.GetHashCode();public override string ToString() => $"ProductId {Value}";public static bool operator ==(ProductId a, ProductId b) => a.Equals(b);public static bool operator !=(ProductId a, ProductId b) => !a.Equals(b);
}
上面的代码没什么难的,但是如果每个实体都需要的话,那确实有点麻烦,在C# 9 可以使用source generators来完成这些,但是C# 9还引入了另一个功能,使用起来更方便。
Record类型
Record 类型是具有内置不变性和值语义的引用类型,它和上面我们写的强类型是一样的(手动写的成员实现Equals,GetHashCode等等),在代码中使用也非常简洁, 如果我们ProductId使用record重写类型,就是下边这样:
public record ProductId(int Value);
是的,您没看错,这是一行,而上面的代码是一大段,它完成了我们手动执行的所有操作(实际上,还多了很多!)。
主要区别在于:我们的手动实现是struct,即值类型,但是记录是引用类型,这意味着它们可以为null,这可能不是主要问题,尤其是在使用可为空的引用类型的情况下,但是要知道这一点。
现在为模型中的每个实体编写一个强类型的id是不是很简单,使用Record 非常方便,当然,还有其他问题需要考虑,例如JSON序列化,与Entity Framework Core一起使用等,但这是另一篇文章的故事!
最后
欢迎扫码关注我们的公众号 【全球技术精选】,专注国外优秀博客的翻译和开源项目分享,也可以添加QQ群 897216102
使用 C# 9 的records作为强类型ID - 初次使用相关推荐
- 使用 C# 9 的records作为强类型ID - JSON序列化
使用 C# 9 的records作为强类型ID - 路由和查询参数 在本系列的上一篇文章中使用 C# 9 的records作为强类型ID - 路由和查询参数,我们注意到强类型ID的实体,序列化为 JS ...
- 使用 C# 9 的records作为强类型ID - 路由和查询参数
上一篇文章,我介绍了使用 C# 9 的record类型作为强类型id,非常简洁 public record ProductId(int Value); 但是在强类型id真正可用之前,还有一些问题需要解 ...
- array column函数php,php array_column 函数实例应用
array_column返回数组中指定的一列 先看一下函数的语法: array array_column(array $input, mixed $column_key, mixed $index_k ...
- Java项目:在线考试系统(java+SSM+mysql+JSP)
源码获取:博客首页 "资源" 里下载! 运行环境:jdk1.8.Mysql5.7.Tomcat8.5.IDEA/Eclipse 功能简介:在线考试.历史回顾.个人成绩查询等. 管理 ...
- Java项目:前台+后台在线考试系统设计和实现(java+Springboot+ssm+mysql+jsp+maven)
源码获取:博客首页 "资源" 里下载! 一.项目简述 本系统主要实现的功能有: 学生以及老师的注册登录,在线考试,错题查询,学生管理,问题管理,错题管理,错题查询,分数查询,试卷管 ...
- jqGrid简单使用
1.jqGrid简单使用: 2.jqGrid常用选项具体含义简介: 3.jqGrid使用json数据格式,以及jsonReader和repeatitems配合使用时json格式的实际变化. 首先,为大 ...
- cas+shiro+spring 单点登录
2019独角兽企业重金招聘Python工程师标准>>> 最近公司在搞单点登录,之前也做过,用的是58同城的wf框架,基于cas 的原理用拦截器自己写的一套.目前用cas+shiro+ ...
- [转]学习Objective-C: 入门教材
学习Objective-C: 入门教材 Objective-C是一种简单的计算机语言,它可以用来设计复杂的面向对象程序. Objective-C扩展了标准ANSI C语言,增加了一些定义类.方法以及其 ...
- innodb一页为什么要存储两行记录_InnoDB中的页合并与分裂
原文标题:InnoDB Page Merging and Page Splitting 原文链接:https://www.percona.com/blog/2017/04/10/innodb-page ...
最新文章
- iOS 动态更换icon
- math标准库函数功能汇总
- odps新手上路之安装Eclipse开发环境
- 用VS2013如何编写C语言
- 应用市场中的应用转让
- logo下方显示技术支持信息_LOGO墙形象设计的几种方案
- AE还是AO了开发小结!!!!!至今没搞懂我用的是AE还是AO
- mongo性能测试demo 代码正确运行
- Ubuntu16.04 pip下载安装tensorflow(GPU版)
- 解决CAS 4.2.7 版本集群部署的各种问题
- 企业选择WMS仓库管理系统免费版是否更好
- Arduino Nano 自制显示器 “流光溢彩” 外设教程(新人向)
- MacBook安裝系統報錯
- 音频播放器—打开音频设备(扬声器)
- java高级人员必读十大书籍!
- 机器学习——XGboost模型
- 电脑监控软件有哪些?具体功能是什么
- word通配符用原文替换原文加某以内容的方式
- 腾讯云服务器突然远程连不上
- 上墙抽奖php代码,年会微信大屏上墙抽奖系统PHP独立后台版源码
热门文章
- Factory Method工厂方法
- Linux学习_菜鸟教程_3
- 社交网络图中结点的“重要性“计算(Dijkstra + SPFA + Floyd + 模板)
- 检查点(Checkpoint)过程如何处理未提交的事务
- Framer – 将视觉搞转换为更真实的动态原型
- 【转】SQL SERVER 存储过程学习笔记
- chemdraw怎么连接两个结构_利用神经结构搜索构建快速准确轻量级的超分辨率网络...
- 如何停止Internet Explorer 11的建议站点?
- mac共享单个磁盘_如何与您的所有设备共享酒店的单个Wi-Fi连接
- android设置时间widget,【Android】时间与日期Widget(DatePicker 与 TimePicker)