• 基于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>
            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)的记录进行测试。

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

    系列文章:

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

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

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

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

    基于SqlSugar的开发框架循序渐进介绍(5)-- 在服务层使用接口注入方式实现IOC控制反转

     《基于SqlSugar的开发框架循序渐进介绍(6)-- 在基类接口中注入用户身份信息接口 

  • 相关阅读:
    线程
    unix架构
    Unix命令
    可重入函数reentrant function
    Eclipse 中 program arguments 与 VM arguments 的区别
    Java中Generics的使用
    Java的Reflection机制
    Java按值传递、按引用传递
    Java label
    LeetCode Merge Intervals
  • 原文地址:https://www.cnblogs.com/wuhuacong/p/16277426.html
Copyright © 2020-2023  润新知