强类型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 - 初次使用相关推荐

  1. 使用 C# 9 的records作为强类型ID - JSON序列化

    使用 C# 9 的records作为强类型ID - 路由和查询参数 在本系列的上一篇文章中使用 C# 9 的records作为强类型ID - 路由和查询参数,我们注意到强类型ID的实体,序列化为 JS ...

  2. 使用 C# 9 的records作为强类型ID - 路由和查询参数

    上一篇文章,我介绍了使用 C# 9 的record类型作为强类型id,非常简洁 public record ProductId(int Value); 但是在强类型id真正可用之前,还有一些问题需要解 ...

  3. array column函数php,php array_column 函数实例应用

    array_column返回数组中指定的一列 先看一下函数的语法: array array_column(array $input, mixed $column_key, mixed $index_k ...

  4. Java项目:在线考试系统(java+SSM+mysql+JSP)

    源码获取:博客首页 "资源" 里下载! 运行环境:jdk1.8.Mysql5.7.Tomcat8.5.IDEA/Eclipse 功能简介:在线考试.历史回顾.个人成绩查询等. 管理 ...

  5. Java项目:前台+后台在线考试系统设计和实现(java+Springboot+ssm+mysql+jsp+maven)

    源码获取:博客首页 "资源" 里下载! 一.项目简述 本系统主要实现的功能有: 学生以及老师的注册登录,在线考试,错题查询,学生管理,问题管理,错题管理,错题查询,分数查询,试卷管 ...

  6. jqGrid简单使用

    1.jqGrid简单使用: 2.jqGrid常用选项具体含义简介: 3.jqGrid使用json数据格式,以及jsonReader和repeatitems配合使用时json格式的实际变化. 首先,为大 ...

  7. cas+shiro+spring 单点登录

    2019独角兽企业重金招聘Python工程师标准>>> 最近公司在搞单点登录,之前也做过,用的是58同城的wf框架,基于cas 的原理用拦截器自己写的一套.目前用cas+shiro+ ...

  8. [转]学习Objective-C: 入门教材

    学习Objective-C: 入门教材 Objective-C是一种简单的计算机语言,它可以用来设计复杂的面向对象程序. Objective-C扩展了标准ANSI C语言,增加了一些定义类.方法以及其 ...

  9. innodb一页为什么要存储两行记录_InnoDB中的页合并与分裂

    原文标题:InnoDB Page Merging and Page Splitting 原文链接:https://www.percona.com/blog/2017/04/10/innodb-page ...

最新文章

  1. iOS 动态更换icon
  2. math标准库函数功能汇总
  3. odps新手上路之安装Eclipse开发环境
  4. 用VS2013如何编写C语言
  5. 应用市场中的应用转让
  6. logo下方显示技术支持信息_LOGO墙形象设计的几种方案
  7. AE还是AO了开发小结!!!!!至今没搞懂我用的是AE还是AO
  8. mongo性能测试demo 代码正确运行
  9. Ubuntu16.04 pip下载安装tensorflow(GPU版)
  10. 解决CAS 4.2.7 版本集群部署的各种问题
  11. 企业选择WMS仓库管理系统免费版是否更好
  12. Arduino Nano 自制显示器 “流光溢彩” 外设教程(新人向)
  13. MacBook安裝系統報錯
  14. 音频播放器—打开音频设备(扬声器)
  15. java高级人员必读十大书籍!
  16. 机器学习——XGboost模型
  17. 电脑监控软件有哪些?具体功能是什么
  18. word通配符用原文替换原文加某以内容的方式
  19. 腾讯云服务器突然远程连不上
  20. 上墙抽奖php代码,年会微信大屏上墙抽奖系统PHP独立后台版源码

热门文章

  1. Factory Method工厂方法
  2. Linux学习_菜鸟教程_3
  3. 社交网络图中结点的“重要性“计算(Dijkstra + SPFA + Floyd + 模板)
  4. 检查点(Checkpoint)过程如何处理未提交的事务
  5. Framer – 将视觉搞转换为更真实的动态原型
  6. 【转】SQL SERVER 存储过程学习笔记
  7. chemdraw怎么连接两个结构_利用神经结构搜索构建快速准确轻量级的超分辨率网络...
  8. 如何停止Internet Explorer 11的建议站点?
  9. mac共享单个磁盘_如何与您的所有设备共享酒店的单个Wi-Fi连接
  10. android设置时间widget,【Android】时间与日期Widget(DatePicker 与 TimePicker)