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

1、数据访问层的实现

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

如对于数据库表的标注:

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

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

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

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

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

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

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

    /// <summary>
    ///DictTypeInfo/// </summary>
    [SugarTable("TB_DictType")]public classDictTypeInfo
{
/// <summary> ///默认构造函数(需要初始化属性的在此处理)/// </summary> publicDictTypeInfo()
{
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 classDictTypePagedDto : PagedAndSortedInputDto, IPagedAndSortedResultRequest
{
/// <summary> ///默认构造函数/// </summary> public DictTypePagedDto() : base() { }/// <summary> ///参数化构造函数/// </summary> /// <param name="skip ///">跳过的数量</param> /// <param name="resultCount">最大结果集数量</param> public DictTypePagedDto(int skipCount, intresultCount)
{
}
/// <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 classDictDataInfo
{
/// <summary> ///默认构造函数(需要初始化属性的在此处理)/// </summary> publicDictDataInfo()
{
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 returnTask.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)
;
returnquery;
}
/// <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 asyncTask BindTree()
{
var pageDto = newDictTypePagedDto();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(stringdictType)
{
//构建分页的条件和查询条件 var pagerDto = new DictDataPagedDto(this.winGridViewPager1.PagerInfo)
{
DictType_ID
=dictType
};
var result = await BLLFactory<DictDataService>.Instance.GetListAsync(pagerDto);//new DictDataService().GetListAsync(pagerDto); returnresult;
}

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

        private async void winGridViewPager1_OnStartExport(objectsender, 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开发框架一样功能。

标签: none

添加新评论