强类型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 - 路由和查询参数

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

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

    在本系列的上一篇文章中,我们注意到强类型ID的实体,序列化为 JSON 的时候报错了,就像这样: { "id": { "value": 1 }, "n ...

  3. 使用强类型实体Id来避免原始类型困扰(一)

    原文地址:https://andrewlock.net/using-strongly-typed-entity-ids-to-avoid-primitive-obsession-part-1/ 作者: ...

  4. angular的ng-repeat使用

    ng-repeat是angular的一个指令,用来循环生成某些东西.常用的是拿到数据循环生成样式展示在视图中. <!--orderStatuses表示$scope传递的数据$scope.orde ...

  5. Jqgrid学习API

    JQGrid是一个在jquery基础上做的一个表格控件,以ajax的方式和服务器端通信. JQGrid Demo 是一个在线的演示项目.在这里,可以知道jqgrid可以做什么事情. 下面是转自其他人b ...

  6. 【转】jqGrid 各种参数 详解

      [原文]http://www.cnblogs.com/younggun/archive/2012/08/27/2657922.htmljqGrid 各种参数 详解 JQGrid JQGrid是一个 ...

  7. Salesforce + AngularJS + Bootstrap

    也可以分成三步: 1. 添加css和js引用: <apex:stylesheet value="https://maxcdn.bootstrapcdn.com/bootstrap/3. ...

  8. 点击jqGrid表格,弹出需要的表格的数据

    首先,我们先定义一个函数,然后在JQuery里面直接引用就可以了, function GetJqGridRowValue(jgrid, code) { var KeyValue = "&qu ...

  9. jqGrid 学习笔记--数据异步加载方法(转)

    var commonQuery = '../importantInfoReport/pageQueryImportantInfoReport.action?type=0'; jQuery(" ...

随机推荐

  1. tornado 作业 简单首页 登录页 个人中心

    s4 index.py 1 import tornado.ioloop 2 import tornado.web 3 import time 4 5 6 class IndexHandler(torn ...

  2. SpringBoot 拦截器和自定义注解判断请求是否合法

    应用场景举例: 当不同身份的用户请求一个接口时,用来校验用户某些身份,这样可以对单个字段数据进行精确权限控制,具体看代码注释 自定义注解 /** * 对比请求的用户身份是否符合 * @author l ...

  3. Python 学习笔记 之 01 - 基础总结

    数据类型 整数 十六进制和八进制使用0开头,0x12f, 010 浮点数 可以用科学记数法,如1.23x10^9 可以写成 12.3e8 ,0.000012可以写成 1.2e-5 空值 用None表示 ...

  4. 如何配置nginx达到只允许域名访问网址,禁止ip访问的效果

    需求:接入阿里云的waf对网站进行防护,但是如果直接通过IP地址访问网站即可绕过阿里云waf,于是希望禁止通过ip访问网站 修改nginx配置文件 在server段里插入如下内容即可 if ($hos ...

  5. Spark-1-调优基本原则

    1基本概念和原则 每一台host上面可以并行N个worker,每一个worker下面可以并行M个executor,task们会被分配到executor上面去执行.Stage指的是一组并行运行的task ...

  6. 多任务-python实现-多线程共享全局变量(2.1.3)

    @ 目录 1.全局变量的修改 2.全局变量在多线程中的共享 3.多线程可能遇到的问题 1.全局变量的修改 代码实现 num = 100 nums = [11,22] def test(): globa ...

  7. Docker 在搭建私有仓库配置镜像时候报错

    今天搞私有镜像报了个错 ,看了,好久原来是 多了个空格 服务失败,因为控制进程退出时带有错误代码.参见"systemctl状态docker".详细信息参见"服务" ...

  8. BST和DST简单的matlab程序(图的广度和深度遍历)

    图的广度和深度遍历,具体内容教材有 clc;clear all;close all; %初始化邻接压缩表compressTable=[1 2;1 3;1 4;2 4;2 5;3 6;4 6;4 7]; ...

  9. Python将文件夹下的文件名写入excel方便统计

    如题,贴代码: 1 ''' 2 #python将某文件夹下的文件名存储到excel中 3 ''' 4 5 #导入所需模块 6 import os 7 import xlwt 8 9 #定义要处理的文件 ...

  10. python之把列表当做队列使用

    把列表当做队列使用,只是在列表中第一个加入的元素,第一个提取出来,拿列表当做队列用,效率并不高.在列表中最后添加或者删除元素速度很快,然而从列表里插入或者从头弹出速度却不快,因为其他所有元素都要一个一 ...