怎样优雅地增删查改(四):创建通用查询基类

文章目录

    • 创建通用查询抽象层
    • 创建通用查询应用层基类
    • 创建通用查询控制器基类
    • [可选]替换RESTfulApi
    • 扩展泛型参数
    • 服务的“渐进式”
    • 使用

上一章我们实现了Employee管理模块,Employee的增删改查是通过其应用服务类,继承自Abp.Application.Services.CrudAppService实现的。

我们将封装通用的应用层,接口以及控制器基类。

创建通用查询抽象层

创建接口ICurdAppService,在这里我们定义了通用的增删改查接口。

其中的泛型参数:

  • TGetOutputDto: Get方法返回的实体Dto
  • TGetListOutputDto: GetAll方法返回的实体Dto
  • TKey: 实体的主键
  • TGetListInput: GetAll方法接收的输入参数
  • TCreateInput: Create方法接收的输入参数
  • TUpdateInput: Update方法接收的输入参数
public interface ICurdAppService<TGetOutputDto, TGetListOutputDto, in TKey, in TGetListInput, in TCreateInput, in TUpdateInput>{Task<TGetOutputDto> GetAsync(TKey id);Task<PagedResultDto<TGetListOutputDto>> GetAllAsync(TGetListInput input);Task<TGetOutputDto> CreateAsync(TCreateInput input);Task<TGetOutputDto> UpdateAsync(TUpdateInput input);Task DeleteAsync(TKey id);
}

创建通用查询应用层基类

创建应用层服务CurdAppServiceBase,它是一个抽象类,继承自Abp.Application.Services.CrudAppService。

代码如下:

public abstract class CurdAppServiceBase<TEntity, TGetOutputDto, TGetListOutputDto,  TKey, TGetListInput,  TCreateInput, TUpdateInput>
: CrudAppService<TEntity, TGetOutputDto, TGetListOutputDto, TKey, TGetListInput, TCreateInput, TUpdateInput>
where TEntity : class, IEntity<TKey>where TGetOutputDto : IEntityDto<TKey>
where TGetListOutputDto : IEntityDto<TKey>
{protected CurdAppServiceBase(IRepository<TEntity, TKey> repository)
: base(repository){}
}

创建通用查询控制器基类

创建控制器类CurdController,继承自AbpControllerBase。并实现ICurdAppService接口。

代码如下:

public abstract class CurdController<ITAppService, TGetOutputDto, TGetListOutputDto,  TKey, TGetListInput,  TCreateInput, TUpdateInput>: AbpControllerBase
where ITAppService : ICurdAppService<TGetOutputDto, TGetListOutputDto,  TKey, TGetListInput,  TCreateInput, TUpdateInput>
where TGetOutputDto : IEntityDto<TKey>
where TGetListOutputDto : IEntityDto<TKey>
{private readonly ITAppService _recipeAppService;public CurdController(ITAppService recipeAppService){_recipeAppService = recipeAppService;}[HttpPost][Route("Create")]public virtual async Task<TGetOutputDto> CreateAsync(TCreateInput input){return await _recipeAppService.CreateAsync(input);}[HttpDelete][Route("Delete")]public virtual async Task DeleteAsync(TKey id){await _recipeAppService.DeleteAsync(id);}[HttpGet][Route("GetAll")]public virtual async Task<PagedResultDto<TGetListOutputDto>> GetAllAsync(TGetListInput input){return await _recipeAppService.GetAllAsync(input);}[HttpGet][Route("Get")]public virtual async Task<TGetOutputDto> GetAsync(TKey id){return await _recipeAppService.GetAsync(id);}[HttpPut][Route("Update")]public virtual async Task<TGetOutputDto> UpdateAsync(TUpdateInput input){return await _recipeAppService.UpdateAsync(input);}
}

[可选]替换RESTfulApi

为了兼容旧版Abp,需更改增删查改服务(CrudAppService)的方法签名,可参考[Volo.Abp升级笔记]使用旧版Api规则替换RESTful Api以兼容老程序,此处不再赘述。

将UpdateAsync,GetListAsync方法封闭:

private new Task<TGetOutputDto> UpdateAsync(TKey id, TUpdateInput input)
{return base.UpdateAsync(id, input);
}
private new Task<PagedResultDto<TGetListOutputDto>> GetListAsync(TGetListInput input)
{return base.GetListAsync(input);
}

封闭原有UpdateAsync, 新增的UpdateAsync方法更改了方法签名:


public virtual async Task<TGetOutputDto> UpdateAsync(TUpdateInput input)
{await CheckUpdatePolicyAsync();var entity = await GetEntityByIdAsync((input as IEntityDto<TKey>).Id);MapToEntity(input, entity);await Repository.UpdateAsync(entity, autoSave: true);return await MapToGetOutputDtoAsync(entity);}

Brief是一种简化的查询实体集合的方法,其返回的Dto不包含导航属性,以减少数据传输量。

新增GetAllAsync和GetAllBriefAsync方法:

public virtual Task<PagedResultDto<TGetListOutputDto>> GetAllAsync(TGetListInput input)
{return this.GetListAsync(input);
}public async Task<PagedResultDto<TGetListBriefOutputDto>> GetAllBriefAsync(TGetListBriefInput input)
{await CheckGetListPolicyAsync();var query = await CreateBriefFilteredQueryAsync(input);var totalCount = await AsyncExecuter.CountAsync(query);var entities = new List<TEntity>();var entityDtos = new List<TGetListBriefOutputDto>();if (totalCount > 0){query = ApplySorting(query, input);query = ApplyPaging(query, input);entities = await AsyncExecuter.ToListAsync(query);entityDtos = ObjectMapper.Map<List<TEntity>, List<TGetListBriefOutputDto>>(entities);}return new PagedResultDto<TGetListBriefOutputDto>(totalCount,entityDtos);}

扩展泛型参数

目前为止,我们的应用层基类继承于Abp.Application.Services.CrudAppService

为了更好的代码重用,我们对泛型参数进行扩展,使用CurdAppServiceBase的类可根据实际业务需求选择泛型参数

其中的泛型参数:

  • TEntity: CRUD操作对应的实体类
  • TEntityDto: GetAll方法返回的实体Dto
  • TKey: 实体的主键
  • TGetListBriefInput: GetAllBrief方法的输入参数
  • TGetListBriefOutputDto: GetAllBrief方法的输出参数

首先扩展ICurdAppService:


public interface ICurdAppService<TEntityDto, in TKey>: ICurdAppService<TEntityDto, TKey, PagedAndSortedResultRequestDto>
{}public interface ICurdAppService<TEntityDto, in TKey, in TGetListInput>: ICurdAppService<TEntityDto, TKey, TGetListInput, TEntityDto>
{}public interface ICurdAppService<TEntityDto, in TKey, in TGetListInput, in TCreateInput>: ICurdAppService<TEntityDto, TKey, TGetListInput, TCreateInput, TCreateInput>
{}public interface ICurdAppService<TEntityDto, in TKey, in TGetListInput, in TCreateInput, in TUpdateInput>: ICurdAppService<TEntityDto, TEntityDto, TKey, TGetListInput, TCreateInput, TUpdateInput>
{}public interface ICurdAppService<TGetOutputDto, TGetListOutputDto, in TKey, in TGetListInput, in TCreateInput, in TUpdateInput>
: ICurdAppService<TGetOutputDto,  TGetListOutputDto, TKey, TGetListInput, TGetListInput, TCreateInput, TUpdateInput>
{}public interface ICurdAppService<TGetOutputDto, TGetListOutputDto, in TKey, in TGetListInput, in TGetListBriefInput, in TCreateInput, in TUpdateInput>
: ICurdAppService<TGetOutputDto, TGetListOutputDto, TGetListOutputDto, TKey, TGetListInput, TGetListBriefInput, TCreateInput, TUpdateInput>
{}public interface ICurdAppService<TGetOutputDto, TGetListOutputDto, TGetListBriefOutputDto, in TKey, in TGetListInput, in TGetListBriefInput, in TCreateInput, in TUpdateInput>{Task<TGetOutputDto> GetAsync(TKey id);Task<PagedResultDto<TGetListOutputDto>> GetAllAsync(TGetListInput input);Task<TGetOutputDto> CreateAsync(TCreateInput input);Task<TGetOutputDto> UpdateAsync(TUpdateInput input);Task DeleteAsync(TKey id);Task<PagedResultDto<TGetListBriefOutputDto>> GetAllBriefAsync(TGetListInput input);}

扩展CurdAppServiceBase:


public abstract class CurdAppServiceBase<TEntity, TEntityDto, TKey>: CurdAppServiceBase<TEntity, TEntityDto, TKey, PagedAndSortedResultRequestDto>where TEntity : class, IEntity<TKey>where TEntityDto : IEntityDto<TKey>
{protected CurdAppServiceBase(IRepository<TEntity, TKey> repository): base(repository){}
}public abstract class CurdAppServiceBase<TEntity, TEntityDto, TKey, TGetListInput>: CurdAppServiceBase<TEntity, TEntityDto, TKey, TGetListInput, TEntityDto>where TEntity : class, IEntity<TKey>where TEntityDto : IEntityDto<TKey>
{protected CurdAppServiceBase(IRepository<TEntity, TKey> repository): base(repository){}
}public abstract class CurdAppServiceBase<TEntity, TEntityDto, TKey, TGetListInput, TCreateInput>: CurdAppServiceBase<TEntity, TEntityDto, TKey, TGetListInput, TCreateInput, TCreateInput>where TEntity : class, IEntity<TKey>where TEntityDto : IEntityDto<TKey>
{protected CurdAppServiceBase(IRepository<TEntity, TKey> repository): base(repository){}
}public abstract class CurdAppServiceBase<TEntity, TEntityDto, TKey, TGetListInput, TCreateInput, TUpdateInput>
: CurdAppServiceBase<TEntity, TEntityDto, TEntityDto, TKey, TGetListInput, TCreateInput, TUpdateInput>
where TEntity : class, IEntity<TKey>
where TEntityDto : IEntityDto<TKey>
{protected CurdAppServiceBase(IRepository<TEntity, TKey> repository): base(repository){}protected override Task<TEntityDto> MapToGetListOutputDtoAsync(TEntity entity){return MapToGetOutputDtoAsync(entity);}protected override TEntityDto MapToGetListOutputDto(TEntity entity){return MapToGetOutputDto(entity);}
}public abstract class CurdAppServiceBase<TEntity, TGetOutputDto, TGetListOutputDto, TKey, TGetListInput, TCreateInput, TUpdateInput>
: CurdAppServiceBase<TEntity, TGetOutputDto, TGetListOutputDto, TKey, TGetListInput, TGetListInput, TCreateInput, TUpdateInput>
where TEntity : class, IEntity<TKey>
where TGetOutputDto : IEntityDto<TKey>
where TGetListOutputDto : IEntityDto<TKey>
{protected CurdAppServiceBase(IRepository<TEntity, TKey> repository): base(repository){}
}public abstract class CurdAppServiceBase<TEntity, TGetOutputDto, TGetListOutputDto, TKey, TGetListInput,  TCreateInput, TUpdateInput>
: CurdAppServiceBase<TEntity, TGetOutputDto, TGetListOutputDto, TGetListOutputDto, TKey, TGetListInput,  TCreateInput, TUpdateInput>
where TEntity : class, IEntity<TKey>
where TGetOutputDto : IEntityDto<TKey>
where TGetListOutputDto : IEntityDto<TKey>
{protected CurdAppServiceBase(IRepository<TEntity, TKey> repository): base(repository){}
}

扩展CurdController

public abstract class CurdController<ITAppService, TEntityDto, TKey>: CurdController<ITAppService, TEntityDto, TKey, PagedAndSortedResultRequestDto>where ITAppService : ICurdAppService<TEntityDto, TKey>where TEntityDto : IEntityDto<TKey>
{protected CurdController(ITAppService appService): base(appService){}
}public abstract class CurdController<ITAppService, TEntityDto, TKey, TGetListInput>: CurdController<ITAppService, TEntityDto, TKey, TGetListInput, TEntityDto>where ITAppService : ICurdAppService<TEntityDto, TKey, TGetListInput>where TEntityDto : IEntityDto<TKey>
{protected CurdController(ITAppService appService): base(appService){}
}public abstract class CurdController<ITAppService, TEntityDto, TKey, TGetListInput, TCreateInput>: CurdController<ITAppService, TEntityDto, TKey, TGetListInput, TCreateInput, TCreateInput>where ITAppService : ICurdAppService<TEntityDto, TKey, TGetListInput, TCreateInput>where TEntityDto : IEntityDto<TKey>
{protected CurdController(ITAppService appService): base(appService){}
}public abstract class CurdController<ITAppService, TEntityDto, TKey, TGetListInput, TCreateInput, TUpdateInput>
: CurdController<ITAppService, TEntityDto, TEntityDto, TKey, TGetListInput, TCreateInput, TUpdateInput>
where ITAppService : ICurdAppService<TEntityDto, TKey, TGetListInput, TCreateInput, TUpdateInput>where TEntityDto : IEntityDto<TKey>
{protected CurdController(ITAppService appService): base(appService){}}public abstract class CurdController<ITAppService, TGetOutputDto, TGetListOutputDto, TKey, TGetListInput, TCreateInput, TUpdateInput>
: CurdController<ITAppService, TGetOutputDto, TGetListOutputDto, TKey, TGetListInput, TGetListInput, TCreateInput, TUpdateInput>
where ITAppService : ICurdAppService<TGetOutputDto, TGetListOutputDto, TKey, TGetListInput, TCreateInput, TUpdateInput>
where TGetOutputDto : IEntityDto<TKey>
where TGetListOutputDto : IEntityDto<TKey>
{protected CurdController(ITAppService appService): base(appService){}}public abstract class CurdController<ITAppService, TGetOutputDto, TGetListOutputDto, TKey, TGetListInput, TGetListBriefInput, TCreateInput, TUpdateInput>
: CurdController<ITAppService, TGetOutputDto, TGetListOutputDto, TGetListOutputDto, TKey, TGetListInput, TGetListBriefInput, TCreateInput, TUpdateInput>
where ITAppService : ICurdAppService<TGetOutputDto, TGetListOutputDto, TKey, TGetListInput, TGetListBriefInput, TCreateInput, TUpdateInput>
where TGetOutputDto : IEntityDto<TKey>
where TGetListOutputDto : IEntityDto<TKey>
where TGetListBriefInput : TGetListInput
{protected CurdController(ITAppService appService): base(appService){}}public abstract class CurdController<ITAppService, TGetOutputDto, TGetListOutputDto, TGetListBriefOutputDto, TKey, TGetListInput, TGetListBriefInput, TCreateInput, TUpdateInput>: AbpControllerBase
where ITAppService : ICurdAppService<TGetOutputDto, TGetListOutputDto, TGetListBriefOutputDto, TKey, TGetListInput, TGetListBriefInput, TCreateInput, TUpdateInput>
where TGetOutputDto : IEntityDto<TKey>
where TGetListOutputDto : IEntityDto<TKey>
where TGetListBriefInput : TGetListInput
{private readonly ITAppService _recipeAppService;public CurdController(ITAppService recipeAppService){_recipeAppService = recipeAppService;}[HttpPost][Route("Create")]public virtual async Task<TGetOutputDto> CreateAsync(TCreateInput input){return await _recipeAppService.CreateAsync(input);}[HttpDelete][Route("Delete")]public virtual async Task DeleteAsync(TKey id){await _recipeAppService.DeleteAsync(id);}[HttpGet][Route("GetAll")]public virtual async Task<PagedResultDto<TGetListOutputDto>> GetAllAsync(TGetListInput input){return await _recipeAppService.GetAllAsync(input);}[HttpGet][Route("Get")]public virtual async Task<TGetOutputDto> GetAsync(TKey id){return await _recipeAppService.GetAsync(id);}[HttpPut][Route("Update")]public virtual async Task<TGetOutputDto> UpdateAsync(TUpdateInput input){return await _recipeAppService.UpdateAsync(input);}[HttpGet][Route("GetAllBrief")]public virtual async Task<PagedResultDto<TGetListBriefOutputDto>> GetAllBriefAsync(TGetListBriefInput input){return await _recipeAppService.GetAllBriefAsync(input);}
}

服务的“渐进式”

在开发业务模块时,我们可以先使用简单的方式提供Curd服务,随着UI复杂度增加,逐步的使用更加复杂的Curd服务。某种程度上来说,即所谓“渐进式”的开发方式。

  • BaseCurd: 基础型,仅包含Create、Update、Delete、Get
  • SimpleCurd: 简单型,包含BaseCurd的所有功能,同时包含GetAll
  • Curd:完整型,包含SimpleCurd的所有功能,同时包含GetAllBrief,GetAllBrief是一种简化的查询实体集合的方法,其返回的Dto不包含导航属性,以减少数据传输量。是最常用的服务类型。
  • ExtendedCurd:扩展型,包含Curd的所有功能,同时包含GetAllBriefWithoutPage,GetAllBriefWithoutPage 适合一些非分页场景,如日历视图,Echarts图表控件等。使用此接口需要注意:由于没有分页限制,需要其他的查询约束条件(比如日期范围),否则会返回大量的数据,影响性能。

我们扩展应用层基类,控制器及其接口

在这里插入图片描述

在这里插入图片描述

使用

以Alarm为例。来实现扩展型Curd服务(ExtendedCurd)。

假设你已完成创建实体、Dto以及配置完成AutoMapper映射

  1. 在Health模块的抽象层中,创建接口IAlarmAppService,继承自IExtendedCurdAppService和IApplicationService。

IApplicationService是ABP框架的接口,所有的应用服务都需要继承自此接口。

public interface IAlarmAppService : IExtendedCurdAppService<AlarmDto, AlarmDto, AlarmBriefDto, long, GetAllAlarmInput, GetAllAlarmInput,  CreateAlarmInput, UpdateAlarmInput>, IApplicationService
{
}
  1. 在Health模块的应用层中,创建AlarmAppService
public class AlarmAppService : ExtendedCurdAppServiceBase<CAH.Health.Alarm.Alarm, AlarmDto, AlarmDto, AlarmBriefDto, long, GetAllAlarmInput, GetAllAlarmInput, CreateAlarmInput, UpdateAlarmInput>, IAlarmAppService
{public AlarmAppService(IRepository<CAH.Health.Alarm.Alarm, long> basicInventoryRepository) : base(basicInventoryRepository){}
}
  1. 在Health模块的HttpApi中,创建AlarmController,并实现IAlarmAppService接口
[Area(HealthRemoteServiceConsts.ModuleName)]
[RemoteService(Name = HealthRemoteServiceConsts.RemoteServiceName)]
[Route("api/Health/alarm")]
public class AlarmController : ExtendedCurdController<IAlarmAppService, AlarmDto, AlarmDto, AlarmBriefDto, long, GetAllAlarmInput, GetAllAlarmInput, CreateAlarmInput, UpdateAlarmInput>, IAlarmAppService
{private readonly IAlarmAppService _alarmAppService;public AlarmController(IAlarmAppService alarmAppService) : base(alarmAppService){_alarmAppService = alarmAppService;}}

运行程序

在这里插入图片描述

可以看到,我们的接口已经包含所有扩展型Curd方法。

下一章我们将实现通用查询接口的按组织架构查询。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.hqwc.cn/news/20253.html

如若内容造成侵权/违法违规/事实不符,请联系编程知识网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

C++—C++程序基础

文章目录 1 数据类型1.1 基本数据类型1.2 字面值常量1.3 左值和右值1.4 引用与指针 2 基本输入输出2.1 输出2.2 输入 3 函数3.1 内联函数3.2 函数的重载 1 数据类型 1.1 基本数据类型 在C中&#xff0c;除了C语言中的int&#xff0c;char&#xff0c;float&#xff0c;double…

(37)安全开关

文章目录 前言 37.1 LED的含义 37.2 配置安全开关 37.3 使用安全开关强制更新I/O板固件 前言 一个安全开关可以用来启用/禁用电机和伺服的输出。该开关控制飞行器的"安全"状态。当处于这种状态时&#xff0c;电机被阻止运行&#xff08;除了在 Planes MANUAL 模…

Redis 实现库存扣减

在日常开发中有很多地方都有类似扣减库存的操作&#xff0c;比如电商系统中的商品库存&#xff0c;抽奖系统中的奖品库存等。这次分享的是库存的操作怎么防止商品被超卖。 解决方案 基于数据库单库存基于数据库多库存基于redis 解决思路 使用mysql数据库&#xff0c;使用一个…

【javaEE面试题(四)线程不安全的原因】【1. 修改共享数据 2. 操作不是原子性 3. 内存可见性 4. 代码顺序性】

4. 多线程带来的的风险-线程安全 (重点) 4.1 观察线程不安全 static class Counter {public int count 0;void increase() {count;} } public static void main(String[] args) throws InterruptedException {final Counter counter new Counter();Thread t1 new Thread(()…

到手价的监测要求和方法

品牌在做电商价格监测时&#xff0c;为什么要对到手价进行监测&#xff0c;这其中的原因还是很显现的&#xff0c;各平台的促销信息众多&#xff0c;如果只监测页面价的低价行为&#xff0c;那将有非常多的低价链接不会被发现&#xff0c;而这也会导致品牌做渠道管控时失去公平…

电脑内存错误怎么办?

内存是电脑的基本配件之一&#xff0c;一款电脑的内存大小能够在一定程度上决定这款电脑的性能。我们在使用电脑的过程中总会出现一些关于内存大大小小的问题&#xff0c;其中电脑提示内存错误的原因是什么?电脑内存错误怎么解决呢? 内存错误的原因 电脑的很多故障往往都会反…

Java锁

1. 乐观锁 乐观锁是一种乐观思想&#xff0c;即认为读多写少&#xff0c;遇到并发写的可能性低&#xff0c;每次去拿数据的时候都认为 别人不会修改&#xff0c;所以不会上锁。 但是在更新的时候会判断一下在此期间别人有没有去更新这个数据&#xff0c;采取在写时先读出当前…

四、程序员如何高质量重构代码?

有道无术&#xff0c;术尚可求也&#xff0c;有术无道止于术。你好&#xff0c;我是程序员雪球&#xff0c;今天和你聊聊程序员重构代码那些事。 程序员重构代码的重要性不言而喻&#xff0c;但如何进行有效的重构呢&#xff1f;下面是一些建议和指导。 为什么要重构&#xff…

leaflet +高德地图纠偏

一、html源码 <!DOCTYPE html> <html><head><meta http-equiv"Content-Type" content"text/html; charsetutf-8" /><title></title><meta charset"utf-8" /><linkrel"stylesheet"href&…

利用远程调试获取Chromium内核浏览器Cookie

前言 本文将介绍不依靠DPAPI的方式获取Chromium内核浏览器Cookie 远程调试 首先我们以edge为例。edge浏览器是基于Chromium的&#xff0c;而Chromium是可以开启远程调试的&#xff0c;开启远程调试的官方文档如下&#xff1a; https://blog.chromium.org/2011/05/remote-deb…

中介者(Mediator)模式

目录 动机使用场景参与者协作效果实现相关模式应用和思考 中介者(Mediator)是对象行为模式&#xff0c;用一个中介对象来封装一系列对象的交互。中介者使各对象不需要显式的相互应用&#xff0c;从而使其耦合松散&#xff0c;而且可以独立的改变他们之间的交互 动机 面向对象设…

【Arduino小车实践】PID应用之四驱小车

一、 PID公式 二、 PID应用的必要性 1. 四驱小车运动 左边两个驱动轮和右边两个驱动轮的速度相同直线右边轮子的速度大于左边轮子的速度左偏右边轮子的速度小于左边轮子的速度 右偏 2. 产生多种运动的原因 小车的4个电机&#xff0c;减速箱以及车轮在物理层面上存在误差&am…