基于SqlSugar的开发框架循序渐进介绍(4)-- 在数据访问基类中对GUID主键进行自动赋值处理
我们在设计数据库表的时候,往往为了方便,主键ID一般采用字符串类型或者GUID类型,这样对于数据库表记录的迁移非常方便,而且有时候可以在处理关联记录的时候,提前对应的ID值。但有时候进行数据记录插入的时候,往往忽略了对ID的赋值处理。为了便于使用或者允许自动赋值,我们可以在数据访问基类中对GUID主键进行自动赋值处理。
1、实体类主键属性的处理
在我们设计基于SqlSugar的框架的时候,实体类定义一个基类Entity<T>,如下代码所示。
[Serializable]public abstract class Entity<TPrimaryKey> : IEntity<TPrimaryKey>{/// <summary> ///实体类唯一主键/// </summary> [SqlSugar.SugarColumn(IsPrimaryKey = true, ColumnDescription = "主键")]public virtual TPrimaryKey Id { get; set; }
一般可以扩展字符串,整形等等类型的实体类。
默认的Entity定义为整形的,如下所示。自增长的整形主键,不需要插入值,它在记录写入的时候获得对应的Id值。
[Serializable]public abstract class Entity : Entity<int>, IEntity
{/// <summary> ///ID 主键,自增长类型/// </summary> [SqlSugar.SugarColumn(IsPrimaryKey = true, IsIdentity = true)]public override int Id { get; set; }
}
对于字符型类型的ID键,可以在构造函数中对ID进行初始化。
/// <summary> ///客户信息///继承自Entity,拥有Id主键属性/// </summary> [SugarTable("T_Customer")]public class CustomerInfo : Entity<string>{/// <summary> ///默认构造函数(需要初始化属性的在此处理)/// </summary> publicCustomerInfo()
{this.Id =System.Guid.NewGuid().ToString();this.CreateTime =System.DateTime.Now;
}
或者我们在数据插入一条新记录的时候,判断主键是否为空,然后赋值给它,或者唯一的GUID值。
使用Guid.NewGuid() 的处理,这样好处就是可以获得一个唯一的GUID值,而弊端是ID是无序的,没有先后顺序,对ID排序就是无意义了。
为了解决这个问题,我们还是引入Abp VNext的规则,生成一个有序的GUID值,同时在数据库访问基类,对插入记录、更新记录的时候,判断ID(对GUID类型或者字符串类型的主键ID)是否为空,为空则赋值一个有序的GUID给它,则可以完美解决问题了。
这样我们定义实体类的时候,ID值可以不初始化,让它保留位空,可以让用户主动设置值或者自动基类处理赋值。
/// <summary> ///客户信息///继承自Entity,拥有Id主键属性/// </summary> [SugarTable("T_Customer")]public class CustomerInfo : Entity<string>{/// <summary> ///默认构造函数(需要初始化属性的在此处理)/// </summary> publicCustomerInfo()
{this.CreateTime =System.DateTime.Now;
}
2、基类判断ID是否为空并赋值
对于GUID或者字符串类型的ID值,为什么设置有序GUID,可以参考链接了解下:
https://github.com/abpframework/abp/blob/48c52625f4c4df007f04d5ac6368b07411aa7521/docs/zh-Hans/Guid-Generation.md
一般情况下,我们利用SqlSugar插入一个新记录的时候,是如下代码
/// <summary> ///创建对象/// </summary> /// <param name="input">实体对象</param> /// <returns></returns> public virtual async Task<bool>InsertAsync(TEntity input)
{return awaitEntityDb.InsertAsync(input);
}
而为了判断Id是否为空,我们需要对ID类型进行判断,判断是否字符串类型或者GUID类型,如果为空则自动赋值它,因此我们在插入前进行一个判断处理,如下代码所示。
/// <summary> ///创建对象/// </summary> /// <param name="input">实体对象</param> /// <returns></returns> public virtual async Task<bool>InsertAsync(TEntity input)
{
SetIdForGuids(input);//如果Id为空,设置有序的GUID值 return awaitEntityDb.InsertAsync(input);
}
其中SetIdForGuids是获得有序GUID的值的函数。
/// <summary> ///为新创建的实体对象,设置主键Id的值为有序的GUID值(GUID类型或者字符串类型试用)/// </summary> public virtual voidSetIdForGuids(TEntity entity)
{if (entity is IEntity<Guid> entityWithGuidId && entityWithGuidId.Id ==Guid.Empty)
{//默认的GUID类型 var guidType =SequentialGuidType.SequentialAsString;switch(this.dbContext.DbType) //根据不同的数据库类型获取合适的生成序列方式 {caseSqlSugar.DbType.SqlServer:
guidType=SequentialGuidType.SequentialAtEnd;break;caseSqlSugar.DbType.MySql:caseSqlSugar.DbType.PostgreSQL:
guidType=SequentialGuidType.SequentialAsString;break;caseSqlSugar.DbType.Oracle:
guidType=SequentialGuidType.SequentialAsBinary;break;
}var guid =GetSequentialGuid(guidType);
entityWithGuidId.Id=guid;
}else if (entity is IEntity<string> entityWithStringId && string.IsNullOrWhiteSpace(entityWithStringId.Id))
{var guid =GetSequentialGuid(SequentialGuidType.SequentialAsString);
entityWithStringId.Id=guid.ToString();
}
}
根据不同的数据库特性类型,构建不同的GUID值,如果是字符串的Id,我们统一采用 SequentialAsString 这个方式,这个也是支持字符串的常规排序处理,这样我们既获得了一个不重复的GUID值,也可以对ID进行排序,它是根据先后顺序排序的。
/// <summary> ///获取可以生成连续的GUID/// </summary> /// <returns></returns> protectedGuid GetSequentialGuid(SequentialGuidType sequentialGuidType)
{//使用指定序列创建的(生成连续的GUID)//参考链接了解细节:(https://github.com/abpframework/abp/blob/48c52625f4c4df007f04d5ac6368b07411aa7521/docs/zh-Hans/Guid-Generation.md) var options = newAbpSequentialGuidGeneratorOptions()
{
DefaultSequentialGuidType=sequentialGuidType//SequentialAtEnd(default) 用于SQL Server.//SequentialAsString 用于MySQL和PostgreSQL.//SequentialAsBinary 用于Oracle. };return newSequentialGuidGenerator(options).Create();
}
添加几个字典类型(字符串ID)的记录进行测试。
可以看到ID的类型前缀部分是一样的,后面变化,以ID正序排序,是根据写入时间顺序处理的。
系列文章:
《
基于SqlSugar的开发框架的循序渐进介绍(1)--框架基础类的设计和使用
》
《
基于SqlSugar的开发框架循序渐进介绍(2)-- 基于中间表的查询处理
》
《
基于SqlSugar的开发框架循序渐进介绍(3)-- 实现代码生成工具Database2Sharp的整合开发
》
《
基于SqlSugar的开发框架循序渐进介绍(4)-- 在数据访问基类中对GUID主键进行自动赋值处理
》
《
基于SqlSugar的开发框架循序渐进介绍(5)-- 在服务层使用接口注入方式实现IOC控制反转
》
《
基于SqlSugar的开发框架循序渐进介绍(6)-- 在基类接口中注入用户身份信息接口
》
《
基于SqlSugar的开发框架循序渐进介绍(7)-- 在文件上传模块中采用选项模式【Options】处理常规上传和FTP文件上传
》
《
基于SqlSugar的开发框架循序渐进介绍(8)-- 在基类函数封装实现用户操作日志记录
》
《
基于SqlSugar的开发框架循序渐进介绍(9)-- 结合Winform控件实现字段的权限控制
》
《
基于SqlSugar的开发框架循序渐进介绍(10)-- 利用axios组件的封装,实现对后端API数据的访问和基类的统一封装处理
》
《
基于SqlSugar的开发框架循序渐进介绍(11)-- 使用TypeScript和Vue3的Setup语法糖编写页面和组件的总结
》
《
基于SqlSugar的开发框架循序渐进介绍(12)-- 拆分页面模块内容为组件,实现分而治之的处理
》
《
基于SqlSugar的开发框架循序渐进介绍(13)-- 基于ElementPlus的上传组件进行封装,便于项目使用
》
《
基于SqlSugar的开发框架循序渐进介绍(14)-- 基于Vue3+TypeScript的全局对象的注入和使用
》
《
基于SqlSugar的开发框架循序渐进介绍(15)-- 整合代码生成工具进行前端界面的生成
》
《
基于SqlSugar的开发框架循序渐进介绍(16)-- 工作流模块的功能介绍
》
《
基于SqlSugar的开发框架循序渐进介绍(17)-- 基于CSRedis实现缓存的处理
》
《
基于SqlSugar的开发框架循序渐进介绍(18)-- 基于代码生成工具Database2Sharp,快速生成Vue3+TypeScript的前端界面和Winform端界面
》