• 基于SqlSugar的数据库访问处理的封装,支持多数据库并使之适应于实际业务开发中(2)


    在上篇随笔《基于SqlSugar的数据库访问处理的封装,支持多数据库并使之适应于实际业务开发中》中介绍了SqlSugar的基础用法,以及实现对常规项目中对数据访问的基类封装,并通过编写单元测试覆盖相关的功能测试,虽然最后编写单元测试的代码就是实际调用数据处理的代码,不过没有界面不太直观,本篇随笔继续深入SqlSugar的使用介绍,介绍基于Winform项目界面的整合测试。

    1、数据访问层的实现

    在上篇随笔,我们介绍了SqlSugar使用起来还是非常简单的,首先定义好和数据表对应的实体类信息,通过特性声明给的方式,声明表名和字段信息(包括主键信息)

    如对于数据库表的标注:

    [SugarTable("TB_DictData")]
    public class DictDataInfo
    {
    }

    以及对字段信息主键的标注

            /// <summary>
            /// 编号
            /// </summary>
            [SugarColumn(IsPrimaryKey = true)]
            public virtual string ID { get; set; }

    或者是自增字段的标注处理

        public class Person 
        {
            //数据库字段
            [SugarColumn(IsPrimaryKey =true,IsIdentity =true)]
            public int Id { get; set; }

    例如我们对于Winform开发框架中的字典数据库,设计关系如下所示。

    我们生成器对应的SQLSugar实体信息如下所示,这些枯燥的工作可以交给配套的代码生成工具Database2sharp来完成。

        /// <summary>
        /// DictTypeInfo
        /// </summary>
        [SugarTable("TB_DictType")]
        public class DictTypeInfo
        {
            /// <summary>
            /// 默认构造函数(需要初始化属性的在此处理)
            /// </summary>
            public DictTypeInfo()
            {
                this.ID = System.Guid.NewGuid().ToString();
                this.LastUpdated = System.DateTime.Now;
    
            }
    
            #region Property Members
    
            [SugarColumn(IsPrimaryKey = true)]
            public virtual string ID { get; set; }
    
            /// <summary>
            /// 类型名称
            /// </summary>
            public virtual string Name { get; set; }
    
            /// <summary>
            /// 字典代码
            /// </summary>
            public virtual string Code { get; set; }
    
            /// <summary>
            /// 备注
            /// </summary>
            public virtual string Remark { get; set; }
    
            /// <summary>
            /// 排序
            /// </summary>
            public virtual string Seq { get; set; }
    
            /// <summary>
            /// 编辑者
            /// </summary>
            public virtual string Editor { get; set; }
    
            /// <summary>
            /// 编辑时间
            /// </summary>
            public virtual DateTime LastUpdated { get; set; }
    
            /// <summary>
            /// 分类:0 客房/1 KTV/2 茶室
            /// </summary>
            public virtual string PID { get; set; }
    
    
            #endregion
    
        }

    同时为了方便条件的分页处理,我们定义一个分页的Dto对象,如下所示。

        /// <summary>
        /// 用于根据条件分页查询,DTO对象
        /// </summary>
        public class DictTypePagedDto : PagedAndSortedInputDto, IPagedAndSortedResultRequest
        {
            /// <summary>
            /// 默认构造函数
            /// </summary>
            public DictTypePagedDto() : base() { }
    
            /// <summary>
            /// 参数化构造函数
            /// </summary>
            /// <param name="skip
            /// ">跳过的数量</param>
            /// <param name="resultCount">最大结果集数量</param>
            public DictTypePagedDto(int skipCount, int resultCount)
            {
            }
            /// <summary>
            /// 使用分页信息进行初始化SkipCount 和 MaxResultCount
            /// </summary>
            /// <param name="pagerInfo">分页信息</param>
            public DictTypePagedDto(PagerInfo pagerInfo) : base(pagerInfo)
            {
            }
    
            #region Property Members
    
            /// <summary>
            /// 不包含的对象的ID,用于在查询的时候排除对应记录
            /// </summary>
            public virtual string ExcludeId { get; set; }
    
            public virtual string Name { get; set; }
    
            public virtual string Code { get; set; }
    
            public virtual string Remark { get; set; }
    
            public virtual string Seq { get; set; }
    
            public virtual string PID { get; set; }
    
            /// <summary>
            /// 创建时间-开始
            /// </summary>
            public DateTime? CreationTimeStart { get; set; }
            /// <summary>
            /// 创建时间-结束
            /// </summary>
            public DateTime? CreationTimeEnd { get; set; }
            #endregion
        }

    同理对于字典项目的实体信息,也是类似的定义方式,如下所示。

        /// <summary>
        /// DictDataInfo
        /// </summary>
        [SugarTable("TB_DictData")]
        public class DictDataInfo
        {
            /// <summary>
            /// 默认构造函数(需要初始化属性的在此处理)
            /// </summary>
            public DictDataInfo()
            {
                this.ID = System.Guid.NewGuid().ToString();
                this.LastUpdated = System.DateTime.Now;
    
            }
    
            #region Property Members
    
            /// <summary>
            /// 编号
            /// </summary>
            [SugarColumn(IsPrimaryKey = true)]
            public virtual string ID { get; set; }
    
            /// <summary>
            /// 字典大类
            /// </summary>
            public virtual string DictType_ID { get; set; }
    
            /// <summary>
            /// 字典名称
            /// </summary>
            public virtual string Name { get; set; }
    
            /// <summary>
            /// 字典值
            /// </summary>
            public virtual string Value { get; set; }
    
            /// <summary>
            /// 备注
            /// </summary>
            public virtual string Remark { get; set; }
    
            /// <summary>
            /// 排序
            /// </summary>
            public virtual string Seq { get; set; }
    
            /// <summary>
            /// 编辑者
            /// </summary>
            public virtual string Editor { get; set; }
    
            /// <summary>
            /// 编辑时间
            /// </summary>
            public virtual DateTime LastUpdated { get; set; }
    
    
            #endregion
    
        }

    最终我们定义完成实体信息后,需要集成上篇随笔提到的数据访问基类,并重写一下查询条件处理,排序的规则信息即可,如下代码所示。

        /// <summary>
        /// 应用层服务接口实现
        /// </summary>
        public class DictTypeService : MyCrudService<DictTypeInfo, string, DictTypePagedDto>
        {
            /// <summary>
            /// 获取字段中文别名(用于界面显示)的字典集合
            /// </summary>
            /// <returns></returns>
            public override Task<Dictionary<string, string>> GetColumnNameAliasAsync()
            {
                var dict = new Dictionary<string, string>();
                #region 添加别名解析
                dict.Add("ID", "编号");
                dict.Add("Name", "类型名称");
                dict.Add("Code", "字典代码");
                dict.Add("Remark", "备注");
                dict.Add("Seq", "排序");
                dict.Add("Editor", "编辑者");
                dict.Add("LastUpdated", "编辑时间");
                dict.Add("PID", "父ID");
                #endregion
    
                return Task.FromResult(dict);
            }
    
            /// <summary>
            /// 自定义条件处理
            /// </summary>
            /// <param name="input">查询条件Dto</param>
            /// <returns></returns>
            protected override ISugarQueryable<DictTypeInfo> CreateFilteredQueryAsync(DictTypePagedDto input)
            {
                var query = base.CreateFilteredQueryAsync(input);
                query = query
                    .WhereIF(!input.ExcludeId.IsNullOrWhiteSpace(), t => t.ID != input.ExcludeId) //不包含排除ID
                    .WhereIF(!string.IsNullOrEmpty(input.Code), t => t.Code == input.Code)
                    .WhereIF(!string.IsNullOrEmpty(input.PID), t => t.PID == input.PID)
                    .WhereIF(!input.Name.IsNullOrWhiteSpace(), t => t.Name.Contains(input.Name)) //如需要精确匹配则用Equals
                    .WhereIF(!input.Remark.IsNullOrWhiteSpace(), t => t.Remark.Contains(input.Remark)) //如需要精确匹配则用Equals
                    .WhereIF(!input.Seq.IsNullOrWhiteSpace(), t => t.Seq.Contains(input.Seq)) //如需要精确匹配则用Equals
    
                    //创建日期区间查询
                    .WhereIF(input.CreationTimeStart.HasValue, s => s.LastUpdated >= input.CreationTimeStart.Value)
                    .WhereIF(input.CreationTimeEnd.HasValue, s => s.LastUpdated <= input.CreationTimeEnd.Value)
                    ;
    
                return query;
            }
    
            /// <summary>
            /// 自定义排序处理
            /// </summary>
            /// <param name="query">可查询LINQ</param>
            /// <param name="input">查询条件Dto</param>
            /// <returns></returns>
            protected override ISugarQueryable<DictTypeInfo> ApplySorting(ISugarQueryable<DictTypeInfo> query, DictTypePagedDto input)
            {
                return base.ApplySorting(query, input).OrderBy(s => s.Seq);
            }
        }

    其中MyCrudService 采用了泛型的定义方式,传入对应的实体类,主键类型,以及排序分页的对象DTO等,方便基类实现强类型的接口处理。

    这个子类我们也可以通过代码生成的方式实现批量生成即可。

    整合到项目里面,把实体类和数据访问的服务类区分不同的目录放置,便于管理即可。

    2、Winform界面的开发和调用数据操作处理

    上面我们完成了数据库表的实体类和对应数据访问服务类的处理后,我们接下来的就是设计Winform界面用来处理相关的数据处理。

    我这里把我的基于微软企业库访问模式的Winform界面部分拷贝过来调整一下,如下界面所示。

     查看和编辑字典大类界面

      编辑字典项目

     对于数据访问类的调用,我们使用了一个工厂类来创建对应的单例应用,如下获取字典大类列表。

            /// <summary>
            /// 绑定树的数据源
            /// </summary>
            private async Task BindTree()
            {
                var pageDto = new DictTypePagedDto();
                var result = await BLLFactory<DictTypeService>.Instance.GetListAsync(pageDto);
                if (result != null)
                {
                    this.tree.DataSource = result.Items;
                    this.tree.ExpandAll();
                }
            }

    而但我们单击某个字典大类的时候,应该列出对应大类下的字典项目,因此获取字典项目的数据操作如下所示。

            /// <summary>
            /// 获取数据
            /// </summary>
            /// <returns></returns>
            private async Task<IPagedResult<DictDataInfo>> GetData(string dictType)
            {
                //构建分页的条件和查询条件
                var pagerDto = new DictDataPagedDto(this.winGridViewPager1.PagerInfo)
                {
                    DictType_ID = dictType
                };
                var result = await BLLFactory<DictDataService>.Instance.GetListAsync(pagerDto);//new DictDataService().GetListAsync(pagerDto);
                return result;
            }

    我们这里使用了分页查询的条件DictDataPagedDto,如果是需要获取全部,我们也可以通过调用GetAllAsync()函数来实现,如下导出全部的时候代码如下所示。

            private async void winGridViewPager1_OnStartExport(object sender, EventArgs e)
            {
                if (this.winGridViewPager1.IsExportAllPage)
                {
                    var result = await BLLFactory<DictDataService>.Instance.GetAllAsync();
                    this.winGridViewPager1.AllToExport = result.Items;
                }
            }

    这些处理都是基类预先定义好的API,我们通过子类强类型传入即可,非常方便,也简化很多代码。

    同样,我们可以通过Get接口获取指定ID的实体信息,如下所示。

                if (!string.IsNullOrEmpty(ID))
                {
                    var info = await BLLFactory<DictDataService>.Instance.GetAsync(ID);
                    if (info != null)
                    {
                        this.txtName.Text = info.Name;
                        this.txtNote.Text = info.Remark;
                        this.txtSeq.Text = info.Seq;
                        this.txtValue.Text = info.Value;
                    }
                }

    在Winform编辑界面中,我们重写保存更新的代码如下所示。

            public override async Task<bool> SaveUpdated()
            {
                var info = await BLLFactory<DictDataService>.Instance.GetAsync(ID);
                if (info != null)
                {
                    SetInfo(info);
    
                    try
                    {
                        return await BLLFactory<DictDataService>.Instance.UpdateAsync(info);
                    }
                    catch (Exception ex)
                    {
                        LogTextHelper.Error(ex);
                        MessageDxUtil.ShowError(ex.Message);
                    }
                }
    
                return false;
            }

    以上是Winform界面中对常规数据处理接口的调用,这些都是通过强类型实体的方式调用基类函数,非常方便快捷,同时以提供了很好的API统一性实现。

    最终界面效果和原先Winform开发框架一样功能。

     

  • 相关阅读:
    WordPress主题开发:数据调用
    WordPress主题开发:style.css主题信息标记
    WordPress主题开发:开启侧边栏小工具功能
    WordPress主题开发:开启导航菜单功能
    Instrument 实用详解
    IOS开发~GCD--讲的巨详细,而且还有例子工程
    CATransition 实践
    让提示界面始终保持在页面的最前端(页面置顶)
    xcode调试查看变量的值
    GCD实现多线程 实践
  • 原文地址:https://www.cnblogs.com/wuhuacong/p/15992688.html
Copyright © 2020-2023  润新知