基于SqlSugar的开发框架循序渐进介绍(2)-- 基于中间表的查询处理
在前面介绍的SqlSugar的相关查询处理操作中,我们主要以单表的方式生成相关的实体类,并在查询的时候,对单表的字段进行条件的对比处理,从而返回对应的数据记录。本篇随笔介绍在一些外键或者中间表的处理中,如何遍历查询并获得所需的记录操作。
1、回顾单表的操作查询
我在《基于SqlSugar的开发框架的循序渐进介绍(1)--框架基础类的设计和使用》中介绍过的Customer表信息,就是一个单表的处理。
例如,我们对于一个简单的客户信息表,如下所示。
生成对应的实体对象CustomerInfo外,同时生成 CustomerPagedDto 的分页查询条件对象。
在继承基类后
/// <summary>
/// 应用层服务接口实现
/// </summary>
public class CustomerService : MyCrudService<CustomerInfo, string, CustomerPagedDto>, ICustomerService
{
....
}
并重写 CreateFilteredQueryAsync 函数,从而实现了条件的精确查询处理。
/// <summary>
/// 应用层服务接口实现
/// </summary>
public class CustomerService : MyCrudService<CustomerInfo, string, CustomerPagedDto>, ICustomerService
{
/// <summary>
/// 自定义条件处理
/// </summary>
/// <param name="input">查询条件Dto</param>
/// <returns></returns>
protected override ISugarQueryable<CustomerInfo> CreateFilteredQueryAsync(CustomerPagedDto input)
{
var query = base.CreateFilteredQueryAsync(input); query = query
.WhereIF(!input.ExcludeId.IsNullOrWhiteSpace(), t => t.Id != input.ExcludeId) //不包含排除ID
.WhereIF(!input.Name.IsNullOrWhiteSpace(), t => t.Name.Contains(input.Name)) //如需要精确匹配则用Equals
//年龄区间查询
.WhereIF(input.AgeStart.HasValue, s => s.Age >= input.AgeStart.Value)
.WhereIF(input.AgeEnd.HasValue, s => s.Age <= input.AgeEnd.Value) //创建日期区间查询
.WhereIF(input.CreateTimeStart.HasValue, s => s.CreateTime >= input.CreateTimeStart.Value)
.WhereIF(input.CreateTimeEnd.HasValue, s => s.CreateTime <= input.CreateTimeEnd.Value)
; return query;
}
在表的对应实体信息没有其他表关联的时候,我们直接通过SqlSugar的基础接口返回对象列表即可。
通过 CreateFilteredQueryAsync 的精确条件处理,我们就可以明确实体类的查询条件处理,因此对于CustomerPagedDto来说,就是可以有客户端传入,服务后端的基类进行处理了。
如基类的分页条件查询函数GetListAsync就是根据这个来处理的,它的实现代码如下所示。
/// <summary>
/// 根据条件获取列表
/// </summary>
/// <param name="input">分页查询条件</param>
/// <returns></returns>
public virtual async Task<PagedResultDto<TEntity>> GetListAsync(TGetListInput input)
{
var query = CreateFilteredQueryAsync(input);
var totalCount = await query.CountAsync(); query = ApplySorting(query, input);
query = ApplyPaging(query, input); var list = await query.ToListAsync(); return new PagedResultDto<TEntity>(
totalCount,
list
);
}
也就是说只要继承了 CustomerService ,我们默认调用基类的 GetListAsync 就可以返回对应的列表记录了。
如在Web API的控制器中调用获取记录返回,调用处理的代码如下所示。
/// <summary>
/// 获取所有记录
/// </summary>
[HttpGet]
[Route("all")]
[HttpGet]public virtual async Task<ListResultDto<TEntity>> GetAllAsync()
{
//检查用户是否有权限,否则抛出MyDenyAccessException异常
base.CheckAuthorized(AuthorizeKey.ListKey); return await _service.GetAllAsync();
}
而对于Winform的调用,我们这里首先利用代码生成工具生成对应的界面和代码
查看其调用的界面代码
而其中GetData中的函数部分内容如下所示。
/// <summary>
/// 获取数据
/// </summary>
/// <returns></returns>
private async Task<IPagedResult<CustomerInfo>> GetData()
{
CustomerPagedDto pagerDto = null;
if (advanceCondition != null)
{
//如果有高级查询,那么根据输入信息构建查询条件
pagerDto = new CustomerPagedDto(this.winGridViewPager1.PagerInfo);
pagerDto = dlg.GetPagedResult(pagerDto);
}
else
{
//构建分页的条件和查询条件
pagerDto = new CustomerPagedDto(this.winGridViewPager1.PagerInfo)
{
//添加所需条件
Name = this.txtName.Text.Trim(),
}; //日期和数值范围定义
//年龄,需在CustomerPagedDto中添加 int? 类型字段AgeStart和AgeEnd
var Age = new ValueRange<int?>(this.txtAge1.Text, this.txtAge2.Text); //数值类型
pagerDto.AgeStart = Age.Start;
pagerDto.AgeEnd = Age.End; //创建时间,需在CustomerPagedDto中添加 DateTime? 类型字段CreationTimeStart和CreationTimeEnd
var CreationTime = new TimeRange(this.txtCreationTime1.Text, this.txtCreationTime2.Text); //日期类型
pagerDto.CreateTimeStart = CreationTime.Start;
pagerDto.CreateTimeEnd = CreationTime.End;
} var result = await BLLFactory<CustomerService>.Instance.GetListAsync(pagerDto);
return result;
}
列表界面效果如下所示。
2、基于中间表的查询处理
前面的查询处理,主要就是针对没有任何关系的表实体对象的返回处理,但往往我们开发的时候,会涉及到很多相关的表,单独的表相对来说还是比较少,因此对表的关系遍历处理和中间表的关系转换,就需要在数据操作的时候考虑的了。
例如对于字典大类和字典项目的关系,如下所示。
以及在权限管理系统模块中,用户、角色、机构、权限等存在着很多中间表的关系,如下所示。
如对于字典表关系处理,我们采用Queryable<DictDataInfo, DictTypeInfo>的查询处理方式,可以联合两个表对象实体进行联合查询,如下代码所示。
/// <summary>
/// 根据字典类型名称获取所有该类型的字典列表集合(Key为名称,Value为值)
/// </summary>
/// <param name="dictTypeName">字典类型名称</param>
/// <returns></returns>
public async Task<Dictionary<string, string>> GetDictByDictType(string dictTypeName)
{
var query = this.Client.Queryable<DictDataInfo, DictTypeInfo>(
(d, t) => d.DictType_ID == t.Id && t.Name == dictTypeName)
.Select(d => d); //联合条件获取对象 query = query.OrderBy(d => d.DictType_ID).OrderBy(d => d.Seq);//排序
var list = await query.ToListAsync();//获取列表 var dict = new Dictionary<string, string>();
foreach (var info in list)
{
if (!dict.ContainsKey(info.Name))
{
dict.Add(info.Name, info.Value);
}
}
return dict;
}
其中的Client对象是DbContext对象实例的Client属性,如下图所示。
这个对象是在DbContext对象中构建的,如下所示。
this.Client = new SqlSugarScope(new ConnectionConfig()
{
DbType = this.DbType,
ConnectionString = this.ConnectionString,
InitKeyType = InitKeyType.Attribute,
IsAutoCloseConnection = true, //是否自动关闭连接
AopEvents = new AopEvents
{
OnLogExecuting = (sql, p) =>
{
//Log.Information(sql);
//Log.Information(string.Join(",", p?.Select(it => it.ParameterName + ":" + it.Value)));
}
}
});
我们查看Queryable,可以看到这个SqlSugar基类函数 Queryable 提供了很多重载函数,也就是它们可以提供更多的表对象进行联合查询的,如下所示。
前面介绍的是外键的一对多的关系查询,通过两个对象之间进行的关系连接,从而实现另一个对象属性的对比查询操作的。
对于中间表的处理,也是类似的情况,我们通过对比中间表的属性,从而实现条件的过滤处理。如下是对于角色中相关关系的中间表查询。
/// <summary>
/// 根据用户ID获取对应的角色列表
/// </summary>
/// <param name="userID">用户ID</param>
/// <returns></returns>
private async Task<List<RoleInfo>> GetByUser(int userID)
{
var query = this.Client.Queryable<RoleInfo, User_RoleInfo>(
(t, m) => t.Id == m.Role_ID && m.User_ID == userID)
.Select(t => t); //联合条件获取对象 query = query.OrderBy(t => t.CreateTime);//排序
var list = await query.ToListAsync();//获取列表
return list;
} /// <summary>
/// 根据机构获取对应的角色列表(判断机构角色中间表)
/// </summary>
/// <param name="ouID">机构的ID</param>
/// <returns></returns>
public async Task<List<RoleInfo>> GetRolesByOu(int ouID)
{
var query = this.Client.Queryable<RoleInfo, OU_RoleInfo>(
(t, m) => t.Id == m.Role_ID && m.Ou_ID == ouID)
.Select(t => t); //联合条件获取对象 query = query.OrderBy(t => t.CreateTime);//排序
var list = await query.ToListAsync();//获取列表
return list;
}
通过联合查询中间表对象信息,可以对它的字段属性进行条件联合,从而获得所需的记录。
这里User_RoleInfo和Ou_RoleInfo表也是根据中间表的属性生成的,不过它们在业务层并没有任何关联操作,也不需要生成对应的Service层,因此只需要生成相关的Model类实体即可。
/// <summary>
/// 用户角色关联
/// </summary>
[SugarTable("T_ACL_User_Role")]
public class User_RoleInfo
{
/// <summary>
/// 用户ID
/// </summary>
[Required]
public virtual int User_ID { get; set; } /// <summary>
/// 角色ID
/// </summary>
[Required]
public virtual int Role_ID { get; set; } }
/// <summary>
/// 机构角色关联
/// </summary>
[SugarTable("T_ACL_OU_Role")]
public class OU_RoleInfo
{
/// <summary>
/// 机构ID
/// </summary>
[Required]
public virtual int Ou_ID { get; set; } /// <summary>
/// 角色ID
/// </summary>
[Required]
public virtual int Role_ID { get; set; }
}
可以看到这两个实体不同于其他实体,它们没有基类继承关系,而一般标准的实体是有的。
/// <summary>
/// 角色信息
/// </summary>
[SugarTable("T_ACL_Role")]
public class RoleInfo : Entity<int> { } /// <summary>
/// 功能菜单
/// </summary>
[SugarTable("T_ACL_Menu")]
public class MenuInfo : Entity<string> { }
所以我们就不需要构建它们的Service层来处理数据,它的存在合理性只是在于能够和其他实体对象进行表的联合查询处理而且。
最后贴上一个整合SqlSugar处理而完成的系统基础框架的Winform端界面,其中包括用户、组织机构、角色管理、权限管理、菜单管理、日志、字典、客户信息等业务表的处理。
以证所言非虚。
基于SqlSugar的开发框架循序渐进介绍(2)-- 基于中间表的查询处理的更多相关文章
- 基于SqlSugar的开发框架循序渐进介绍(3)-- 实现代码生成工具Database2Sharp的整合开发
我喜欢在一个项目开发模式成熟的时候,使用代码生成工具Database2Sharp来配套相关的代码生成,对于我介绍的基于SqlSugar的开发框架,从整体架构确定下来后,我就着手为它们量身定做相关的代码 ...
- 基于SqlSugar的开发框架循序渐进介绍(4)-- 在数据访问基类中对GUID主键进行自动赋值处理
我们在设计数据库表的时候,往往为了方便,主键ID一般采用字符串类型或者GUID类型,这样对于数据库表记录的迁移非常方便,而且有时候可以在处理关联记录的时候,提前对应的ID值.但有时候进行数据记录插入的 ...
- 基于SqlSugar的开发框架循序渐进介绍(5)-- 在服务层使用接口注入方式实现IOC控制反转
在前面随笔,我们介绍过这个基于SqlSugar的开发框架,我们区分Interface.Modal.Service三个目录来放置不同的内容,其中Modal是SqlSugar的映射实体,Interface ...
- 基于SqlSugar的开发框架循序渐进介绍(6)-- 在基类接口中注入用户身份信息接口
在基于SqlSugar的开发框架中,我们设计了一些系统服务层的基类,在基类中会有很多涉及到相关的数据处理操作的,如果需要跟踪具体是那个用户进行操作的,那么就需要获得当前用户的身份信息,包括在Web A ...
- 基于SqlSugar的开发框架循序渐进介绍(8)-- 在基类函数封装实现用户操作日志记录
在我们对数据进行重要修改调整的时候,往往需要跟踪记录好用户操作日志.一般来说,如对重要表记录的插入.修改.删除都需要记录下来,由于用户操作日志会带来一定的额外消耗,因此我们通过配置的方式来决定记录那些 ...
- 基于SqlSugar的开发框架循序渐进介绍(12)-- 拆分页面模块内容为组件,实现分而治之的处理
在早期的随笔就介绍过,把常规页面的内容拆分为几个不同的组件,如普通的页面,包括列表查询.详细资料查看.新增资料.编辑资料.导入资料等页面场景,这些内容相对比较独立,而有一定的代码量,本篇随笔介绍基于V ...
- 基于SqlSugar的开发框架循序渐进介绍(13)-- 基于ElementPlus的上传组件进行封装,便于项目使用
在我们实际项目开发过程中,往往需要根据实际情况,对组件进行封装,以更简便的在界面代码中使用,在实际的前端应用中,适当的组件封装,可以减少很多重复的界面代码,并且能够非常简便的使用,本篇随笔介绍基于El ...
- 基于SqlSugar的开发框架循序渐进介绍(14)-- 基于Vue3+TypeScript的全局对象的注入和使用
刚完成一些前端项目的开发,腾出精力来总结一些前端开发的技术点,以及继续完善基于SqlSugar的开发框架循序渐进介绍的系列文章,本篇随笔主要介绍一下基于Vue3+TypeScript的全局对象的注入和 ...
- 基于SqlSugar的开发框架循序渐进介绍(15)-- 整合代码生成工具进行前端界面的生成
在前面随笔<基于SqlSugar的开发框架循序渐进介绍(12)-- 拆分页面模块内容为组件,实现分而治之的处理>中我们已经介绍过,对于相关的业务表的界面代码,我们已经尽可能把不同的业务逻辑 ...
- 基于SqlSugar的开发框架循序渐进介绍(17)-- 基于CSRedis实现缓存的处理
在一个应用系统的开发框架中,往往很多地方需要用到缓存的处理,有些地方是为了便于记录用户的数据,有些地方是为了提高系统的响应速度,如有时候我们在发送一个短信验证码的时候,可以在缓存中设置几分钟的过期时间 ...
随机推荐
- 学习SVN03
SVN版本控制系统最佳实践 第1章SVN介绍及应用场景 1.1什么是SVN(Subversion) Svn(subversion)是近年来崛起非常优秀的版本管理工具,与CVS管理工具一样,SVN是 ...
- mian中的argv调用时为什么不是*argv
c++main函数char * argv[]是个指针数组,元素是指针,为何argv[1]得到不是地址? 照我的理解char *argv[]保存的应该是一组指针,即地址,每个地址中保存的是char类型变 ...
- CSS5:移动端页面(响应式)
CSS5:移动端页面(响应式) 如果手机端和PC端页面差别很大,就不要写响应式,不要写@media 就直接将两个页面拆开成两个文件就可以了.关于判断是手机端你还是PC端,就交给后端来做只有一些新闻站点 ...
- 记录axios高效率并发的方法
// 首先我的请求是统一管理 方便创建拦截器 export function login(parameter) { return axios({ url: api.Login, ...
- 纹理集打包和动画转换工具Texture Merge的使用教程
Texture Merger 可将零散纹理拼合为整图,同时也可以解析SWF.GIF动画,制作Egret位图文本,导出可供Egret使用的配置文件,其纹理集制作功能在小游戏开发中可以起到降低小游戏包体的 ...
- 人机交互大作业--flash嵌入web(纯界面)
界面: 源代码:最近较忙,后续会上传至github
- vuecli中配置webpack加快打包速度
webpack4中webpack 的DllPlugin插件可以将常见的库文件作为dll文件来,每次打包的时候就不用再次打包库文件了. 但是游鱼西在vuecli中已经去除这个选项,意识到带来的打包速度提 ...
- JavaEE期末复习知识点总结
JavaEE期末复习知识点总结 Java企业应用开发环境 Maven的基础概念 Maven是一个项目管理工具,可以对 Java 项目进行构建.依赖管理 Maven仓库 Maven 仓库是项目中依赖的第 ...
- Java---变量和基本数据类型
变量 在Java中,变量分为两种:基本类型的变量和引用类型的变量. 在Java中变量必须先定义后使用,在定义变量的时候可以给它一个初始值.如果不写初始值,默认为0或空. 变量的一个重要特点是可以重新赋 ...
- JVM诊断及工具笔记(4) 使用visualvm分析JVM堆内存泄漏
在这里感谢最近一直阅读我文章的小伙伴,如果觉得文章对你有用,可以帮忙关注转载,需要的时候可以及时找到文章. 背景 今年Q3季度我们在推广业务方使用Iceberg,当时为了让不同业务线的用户可以使用自己 ...