11

基于SqlSugar的开发框架循序渐进介绍(4)-- 在数据访问基类中对GUID主键进行自动赋值...

 2 years ago
source link: https://www.cnblogs.com/wuhuacong/p/16277426.html
Go to the source link to view the article. You can view the picture content, updated content and better typesetting reading experience. If the link is broken, please click the button below to view the snapshot at that time.

我们在设计数据库表的时候,往往为了方便,主键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>
        public CustomerInfo()
        {
            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>
        public CustomerInfo()
        {
            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 await EntityDb.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 await EntityDb.InsertAsync(input); 
        }

其中SetIdForGuids是获得有序GUID的值的函数。

        /// <summary>
        /// 为新创建的实体对象,设置主键Id的值为有序的GUID值(GUID类型或者字符串类型试用)
        /// </summary>
        public virtual void SetIdForGuids(TEntity entity)
        {
            if (entity is IEntity<Guid> entityWithGuidId && entityWithGuidId.Id == Guid.Empty)
            {
                //默认的GUID类型
                var guidType = SequentialGuidType.SequentialAsString;

                switch(this.dbContext.DbType) //根据不同的数据库类型获取合适的生成序列方式
                {
                    case SqlSugar.DbType.SqlServer:
                        guidType = SequentialGuidType.SequentialAtEnd;
                        break;
                    case SqlSugar.DbType.MySql:
                    case SqlSugar.DbType.PostgreSQL:
                        guidType = SequentialGuidType.SequentialAsString;
                        break;
                    case SqlSugar.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>
        protected Guid GetSequentialGuid(SequentialGuidType sequentialGuidType)
        {//使用指定序列创建的(生成连续的GUID)
            //参考链接了解细节:(https://github.com/abpframework/abp/blob/48c52625f4c4df007f04d5ac6368b07411aa7521/docs/zh-Hans/Guid-Generation.md)
            var options = new AbpSequentialGuidGeneratorOptions()
            {
                DefaultSequentialGuidType = sequentialGuidType
                //SequentialAtEnd(default) 用于SQL Server.
                //SequentialAsString 用于MySQL和PostgreSQL.
                //SequentialAsBinary 用于Oracle.
            };
            return new SequentialGuidGenerator(options).Create();
        }

添加几个字典类型(字符串ID)的记录进行测试。

8867-20220516165304099-1822045649.png

 可以看到ID的类型前缀部分是一样的,后面变化,以ID正序排序,是根据写入时间顺序处理的。

8867-20220516165523659-677252460.png

系列文章:

基于SqlSugar的开发框架的循序渐进介绍(1)--框架基础类的设计和使用

基于SqlSugar的开发框架循序渐进介绍(2)-- 基于中间表的查询处理

基于SqlSugar的开发框架循序渐进介绍(3)-- 实现代码生成工具Database2Sharp的整合开发

基于SqlSugar的开发框架循序渐进介绍(4)-- 在数据访问基类中对GUID主键进行自动赋值处理 


About Joyk


Aggregate valuable and interesting links.
Joyk means Joy of geeK