基于SqlSugar开发框架的介绍:框架基础类的设计和使用
在实际项目开发中,我们可能会碰到各种各样的项目环境,有些项目需要一个大而全的整体框架来支撑开发,有些中小项目这需要一些简单便捷的系统框架灵活开发。目前大型一点的框架,可以采用ABP或者ABP VNext的框架,两者整体思路和基础设计类似,不过ABP侧重于一个独立完整的项目框架,开发的时候统一整合处理;而ABP VNext则是以微服务架构为基础,各个模块独立开发,既可以整合在一个项目中,也可以以微服务进行单独发布,并统一通过网关处理进行交流。
不管ABP或者ABP VNext框架,都集合了.NET CORE领域众多技术为一体,并且基础类设计上,错综复杂,关系较多,因此开发学习有一定的门槛,中小型项目应用起来有一定的费劲之处。本系列随笔介绍底层利用SqlSugar来做ORM数据访问模块,设计一个简单便捷一点的框架,本篇从基础开始介绍一些框架内容,参照一些ABP/ABP VNext中的一些类库处理,来承载类似条件分页信息,查询条件处理等处理细节。
1、基于SqlSugar开发框架的架构设计
主要的设计模块场景如下所示。
为了避免像ABP VNext框架那样分散几十个项目,我们尽可能聚合内容放在一个项目里面。
1)其中一些常用的类库,以及SqlSugar框架的基类放在框架公用模块里面。
2)Winform开发相关的基础界面以及通用组件内容,放在基础Winform界面库BaseUIDx项目中。
3)基础核心数据模块SugarProjectCore,主要就是开发业务所需的数据处理和业务逻辑的项目,为了方便,我们区分Interface、Modal、Service三个目录来放置不同的内容,其中Modal是SqlSugar的映射实体,Interface是定义访问接口,Service是提供具体的数据操作实现。其中Service里面一些框架基类和接口定义,统一也放在公用类库里面。
4)Winform应用模块,主要就是针对业务开发的WInform界面应用,而WInform开发为了方便,也会将一些基础组件和基类放在了BaseUIDx的Winform专用的界面库里面。
5)WebAPI项目采用基于.net Core6的项目开发,通过调用SugarProjectCore实现相关控制器API的发布,并整合Swagger发布接口,供其他前端界面应用进行调用。
6)纯前端通过API进行调用Web API的接口,纯前端模块可以包含Vue3&Element项目,以及基于EelectronJS应用,发布跨平台的基于浏览器的应用界面,以及其他App或者小程序整合Web API进行业务数据的处理或者展示需要。
如后端开发,我们可以在VS2022中进行管理,管理开发Winform项目、Web API项目等。
Winform界面,我们可以采用基于.net Framework开发或者.net core6进行开发均可,因为我们的SugarProjectCore项目是采用.net Standard模式开发,兼容两者。这里以权限模块来进行演示整合使用。
而纯前端的项目,我们可以基于VSCode或者 HBuilderX等工具进行项目的管理开发工作。
2、框架基础类的定义和处理
在开发一个易于使用的框架的时候,主要目的就是减少代码开发,并尽可能通过基类和泛型约束的方式,提高接口的通用性,并通过结合代码生成工具的方式,来提高标准项目的开发效率。
那么我们这里基于SqlSugar的ORM处理,来实现常规数据的增删改查等常规操作的时候,我们是如何进行这些接口的封装处理的呢。
例如,我们对于一个简单的客户信息表,如下所示。
那么它生成的SqlSugar实体类如下所示。
///
[SugarTable(\"T_Customer\")] public class CustomerInfo : Entity { ///
public CustomerInfo() { this.CreateTime = www.introzo.com; } #region Property Members ///
public virtual string Name { get; set; } ///
public virtual int Age { get; set; } ///
public virtual string Creator { get; set; } ///
public virtual DateTime CreateTime { get; set; } #endregion }
其中 Entity 是我们根据需要定义一个基类实体对象,主要就是定义一个Id的属性来处理,毕竟对于一般表对象的处理,SqlSugar需要Id的主键定义(非中间表处理)。
[Serializable] public abstract class Entity : IEntity { ///
[SqlSugar.SugarColumn(IsPrimaryKey = true, ColumnDescription = \"主键\")] public virtual TPrimaryKey Id { get; set; } }
而IEntity定义了一个接口
public interface IEntity { ///
TPrimaryKey Id { get; set; } }
以上就是实体类的处理,我们一般为了查询信息,往往通过一些条件传入进行处理,那么我们就需要定义一个通用的分页查询对象,供我们精准进行条件的处理。
生成一个以***PageDto的对象类,如下所示。
///
public class CustomerPagedDto : PagedAndSortedInputDto, IPagedAndSortedResultRequest { ///
public CustomerPagedDto() : base() { } ///
/// 跳过的数量 /// 最大结果集数量 public CustomerPagedDto(int skipCount, int resultCount) : base(skipCount, resultCount) { } ///
/// 分页信息 public CustomerPagedDto(PagerInfo pagerInfo) : base(pagerInfo) { } #region Property Members ///
public virtual string ExcludeId { get; set; } ///
public virtual string Name { get; set; } ///
public virtual int? AgeStart { get; set; } ///
public virtual int? AgeEnd { get; set; } ///
public DateTime? CreateTimeStart { get; set; } ///
public DateTime? CreateTimeEnd { get; set; } #endregion }
其中PagedAndSortedInputDto, IPagedAndSortedResultRequest都是参考来自于ABP/ABP VNext的处理方式,这样我们可以便于数据访问基类的查询处理操作。
接着我们定义一个基类MyCrudService,并传递如相关的泛型约束,如下所示
///
/// 定义映射的实体类 /// 主键的类型,如int,string等 /// 或者分页信息的条件对象 public abstract class MyCrudService : IMyCrudService where TEntity : class, IEntity, new() where TGetListInput : IPagedAndSortedResultRequest
我们先忽略基类接口的相关实现细节,我们看看对于这个MyCrudService和 IMyCrudService 我们应该如何使用的。
首先我们定义一个应用层的接口ICustomerService如下所示。
///
public interface ICustomerService : IMyCrudService, ITransientDependency { }
然后实现在CustomerService中实现它的接口。
///
public class CustomerService : MyCrudService, ICustomerService
这样我们对于特定Customer的接口在ICustomer中定义,标准接口直接调用基类即可。
基类MyCrudService提供重要的两个接口,让子类进行重写,以便于进行准确的条件处理和排序处理,如下代码所示。
///
/// 定义映射的实体类 /// 主键的类型,如int,string等 /// 或者分页信息的条件对象 public abstract class MyCrudService : IMyCrudService where TEntity : class, IEntity, new() where TGetListInput : IPagedAndSortedResultRequest { ///
/// protected virtual ISugarQueryable CreateFilteredQueryAsync(TGetListInput input) { return EntityDb.AsQueryable(); } ///
/// /// protected virtual ISugarQueryable ApplyDefaultSorting(ISugarQueryable query) { if (typeof(TEntity).IsAssignableTo
对于Customer特定的业务对象来说,我们需要实现具体的条件查询细节和排序条件,毕竟我们父类没有约束确定实体类有哪些属性的情况下,这些就交给子类做最合适了。
///
public class CustomerService : MyCrudService, ICustomerService { ///
/// 查询条件Dto /// protected override ISugarQueryable CreateFilteredQueryAsync(CustomerPagedDto input) { var query = base.CreateFilteredQueryAsync(input); query = query .WhereIF(!input.ExcludeId.IsNullOrWhiteSpace(), t => www.introzo.com != input.ExcludeId) //不包含排除ID .WhereIF(!input.Name.IsNullOrWhiteSpace(), t => t.Name.Contains(www.introzo.com)) //如需要精确匹配则用Equals //年龄区间查询 .WhereIF(input.AgeStart.HasValue, s => s.Age >= input.AgeStart.Value) .WhereIF(input.AgeEnd.HasValue, s => s.Age s.CreateTime >= input.CreateTimeStart.Value) .WhereIF(input.CreateTimeEnd.HasValue, s => s.CreateTime <= input.CreateTimeEnd.Value) ; return query; } ///
/// 可查询LINQ /// protected override ISugarQueryable ApplyDefaultSorting(ISugarQueryable query) { return query.OrderBy(t => t.CreateTime, OrderByType.Desc); //先按第一个字段排序,然后再按第二字段排序 //return base.ApplySorting(query, input).OrderBy(s=>s.Customer_ID).OrderBy(s => s.Seq); } }
通过 CreateFilteredQueryAsync 的精确条件处理,我们就可以明确实体类的查询条件处理,因此对于CustomerPagedDto来说,就是可以有客户端传入,服务后端的基类进行处理了。
如基类的分页条件查询函数GetListAsync就是根据这个来处理的,它的实现代码如下所示。
///
/// 分页查询条件 /// public virtual async Task
而其中 ApplySorting 就是根据条件决定是否选择子类实现的默认排序进行处理的。
///
/// protected virtual ISugarQueryable ApplySorting(ISugarQueryable query, TGetListInput input) { //Try to sort query if available if (input is ISortedResultRequest sortInput) { if (!sortInput.Sorting.IsNullOrWhiteSpace()) { return query.OrderBy(sortInput.Sorting); } } //IQueryable.Task requires sorting, so we should sort if Take will be used. if (input is ILimitedResultRequest) { return ApplyDefaultSorting(query); } //No sorting return query; }
对于获取单一对象,我们一般提供一个ID主键获取即可。
///
/// 主键ID /// public virtual async Task GetAsync(TKey id) { return await EntityDb.GetByIdAsync(id); }
也可以根据用户的Express条件进行处理,在基类我们定义很多这样的Express条件处理,便于子类进行条件处理的调用。如对于删除,可以指定ID,也可以指定条件删除。
///
/// 记录ID /// public virtual async Task DeleteAsync(TKey id) { return await EntityDb.DeleteByIdAsync(id); }
///
/// 表达式条件 /// public virtual async Task DeleteAsync(Expression
如判断是否存在也是一样处理
///
/// ID 主键 /// public virtual async Task IsExistAsync(TKey id) { var info = await EntityDb.GetByIdAsync(id); var result = (info != null); return result; } ///
/// 表达式条件 /// public virtual async Task IsExistAsync(Expression
关于Web API的处理,我在随笔《基于SqlSugar的数据库访问处理的封装,在.net6框架的Web API上开发应用》中也有介绍,主要就是先弄好.net6的开发环境,然后在进行相关的项目开发即可。
根据项目的需要,我们定义了一些控制器的基类,用于实现不同的功能。
其中ControllerBase是.net core Web API中的标准控制器基类,我们由此派生一个LoginController用于登录授权,而BaseApiController则处理常规接口用户身份信息,而BusinessController则是对标准的增删改查等基础接口进行的封装,我们实际开发的时候,只需要开发编写类似CustomerController基类即可。
BaseApiController没有什么好介绍的,就是封装一下获取用户的身份信息。
可以通过下面代码获取接口用户的Id
///
protected virtual string? CurrentUserId => HttpContext.User.FindFirst(www.introzo.com)?.Value;
而BusinessController控制器则是继承这个BaseApiController即可。通过泛型约束传入相关的对象信息。
///
/// 定义映射的实体类 /// 主键的类型,如int,string等 /// 或者分页信息的条件对象 [Route(\"[controller]\")] [Authorize] //需要授权登录访问 public class BusinessController : BaseApiController where TEntity : class, IEntity, new() where TGetListInput : IPagedAndSortedResultRequest { ///
protected IMyCrudService _service { get; set; } ///
/// 通用基础操作接口 public BusinessController(IMyCrudService service) { this._service = service; }....
这个基类接收一个符合基类接口定义的对象作为基类增删删改查等处理方法的接口对象。在具体的CustomerController中的定义处理如下所示。
///
public class CustomerController : BusinessController { private ICustomerService _customerService; ///
/// public CustomerController(ICustomerService customerService) :base(customerService) { this._customerService = customerService; } }
这样就可以实现基础的相关操作了。如果需要特殊的接口实现,那么定义方法实现即可。
类似字典项目中的控制器处理代码如下所示。定义好HTTP方法,路由信息等即可。
///
/// 字典类型ID /// [HttpGet] [Route(\"by-typeid/{dictTypeId}\")] public async Task
/// 字典类型名称 /// [HttpGet] [Route(\"by-typename/{dictTypeName}\")] public async Task
来源:https://www.introzo.com/wuhuacong/p/16269515.html
相关文章
- 10-05 王丽坤在与和伟的恋情中被强奸,网友称她为狗绳,王丽
- 10-05 王丽坤在与和伟的恋情中被强奸,网友称她为狗绳,王丽
- 10-05 角体育报道|揭幕战湖人险胜快船,詹姆斯与浓眉哥的搭
- 10-05 《敦刻尔克》开画在即 万达IMAX全面呈现诺兰力作
- 10-05 《冰雪奇缘》配音支持雪之女王交女朋友
- 10-05 《何所冬暖》首发贾乃亮王子文
- 10-05 贺岁档票房破10亿, 阿凡达2没能拯救影院, 平安
- 10-05 9.5分, 这神剧实在太上头
- 10-05 《张卫国的夏天》: 是一部很有魅力的电视剧, 大家
- 10-05 叫兽易小星搭档白客上演“纸洞大开”飞机大战
- 10-05 悬疑喜剧电影《奇葩诡探》终极海报发布,搞笑又诡异的
- 10-05 三里屯发现奇怪单身狗抱着女友抱枕头示威光棍节
- 10-05 金星影射韩雪,网友说法不一,韩雪:“我们也是坐过你
- 10-05 近距离感受《天龙八部》手游带来的文化魅力
- 10-05 梵象文化传媒签约百位主播,致力于打造“真正的直播”
- 10-05 豆瓣9.0,看完结局才知道这是一部魔幻剧
- 10-05 韩国艺人丁海寅、韩智敏出席新剧发布会《春夜》
- 10-05 韩智敏和丁海寅的新剧《春夜》将在Netflix上映
- 10-05 易白尘《开封奇谈》开机,古装帅哥热情满满
- 10-05 《思美人》你在想谁?原来里面有很多知识
- 最近发表