GUID 生成
GUID 是数据库管理系统中使用的常见主键类型。并且 ABP 框架假定用户 ID 始终是 GUID 类型。
IGuidGenerator 接口服务
GUID 的最主要的问题是默认情况下它不是连续的。 当将 GUID 用作主键并将其设置为表的索引(默认设置)时,会在插入时带来严重的性能问题(因为插入新记录可能需要对现有记录进行重新排序)。
所以,不要使用 Guid.NewGuid() 为您的实体创建 ID。ABP 框架提供 IGuidGenerator 服务用于创建连续的 GUID。
1using System;2using System.Threading.Tasks;3using Volo.Abp.DependencyInjection;4using Volo.Abp.Domain.Repositories;5using Volo.Abp.Guids;6
7namespace AbpDemo8{9 public class MyProductService : ITransientDependency10 {11 private readonly IRepository<Product, Guid> _productRepository;12 private readonly IGuidGenerator _guidGenerator;13
14 public MyProductService(IRepository<Product, Guid> productRepository, IGuidGenerator guidGenerator)15 {10 collapsed lines
16 _productRepository = productRepository;17 _guidGenerator = guidGenerator;18 }19
20 public async Task TestCreateGUIDAsync(string productName)21 {22 Guid guid = _guidGenerator.Create();23 }24 }25}- IGuidGenerator.Create() 用于创建连续的
Guid。
配置
AbpSequentialGuidGeneratorOptions
AbpSequentialGuidGeneratorOptions 是用于配置顺序 GUID 生成的选项类,它具有一个枚举类型属性。 - DefaultSequentialGuidType(类型为 SequentialGuidType 的枚举):生成 GUID 值时使用的策略。
数据库在处理 GUID 时会有所不同,因此您应根据指定数据库进行设置 - SequentialAtEnd SQL Server - SequentialAsString MySQL or PostgreSQL - SequentialAsBinary Oracle
在模块的 ConfigureServices 中进行配置
1Configure<AbpSequentialGuidGeneratorOptions>(options =>2{3 options.DefaultSequentialGuidType = SequentialGuidType.SequentialAsBinary;4});看源码
源码位置 Volo.Abp.Guids\Volo\Abp\Guids\SequentialGuidGenerator.cs
1public Guid Create(SequentialGuidType guidType)2{3 var randomBytes = new byte[10];4 RandomNumberGenerator.GetBytes(randomBytes); // 先生成 10 字节的随机内容5
6 long timestamp = DateTime.UtcNow.Ticks / 10000L;// 获取当前时间戳的值 / 100007
8 byte[] timestampBytes = BitConverter.GetBytes(timestamp);9
10 if (BitConverter.IsLittleEndian)11 {12 Array.Reverse(timestampBytes);13 }14
15 byte[] guidBytes = new byte[16]; // 用于存储最终生成 Guid 的数组27 collapsed lines
16
17 switch (guidType)18 {19 // 可以看到 MySQL、PostgreSQL、Oracle 他们三个对 Guid 的处理方式是一样的20 case SequentialGuidType.SequentialAsString:21 case SequentialGuidType.SequentialAsBinary:22
23 Buffer.BlockCopy(timestampBytes, 2, guidBytes, 0, 6);24 Buffer.BlockCopy(randomBytes, 0, guidBytes, 6, 10);25
26 if (guidType == SequentialGuidType.SequentialAsString && BitConverter.IsLittleEndian)27 {28 Array.Reverse(guidBytes, 0, 4);29 Array.Reverse(guidBytes, 4, 2);30 }31
32 break;33 // SQL Server 独出一家34 case SequentialGuidType.SequentialAtEnd:35
36 Buffer.BlockCopy(randomBytes, 0, guidBytes, 0, 10);37 Buffer.BlockCopy(timestampBytes, 2, guidBytes, 10, 6);38 break;39 }40
41 return new Guid(guidBytes);42}- 他的生成方式就是一个随机的 10 byte 的内容与当前时间 6 byte 相关的一个拼接,最终生成一个二进制长度为 128 位的 Guid。