【从零开始搭建自己的.NET Core Api框架】(六)泛型仓储的作用
系列目录
三. 集成轻量级ORM框架——SqlSugar
六. 集成泛型仓储
源码下载:https://github.com/WangRui321/RayPI_V2.0
注:以下项目里的Service层其实是DAL层的意思,以前都习惯写DAL的,经园友回复提醒,Service一般指业务逻辑层,用Service确实不准确,下个版本更新会更正一下~
1. 根
之前在集成SqlSugar的时候,我们用Student类作为例子,写了5个基础的接口:获取集合、获取单个、添加、修改、删除,也就是常说的仓储的CRUD了。
Service层的代码是这样的:
而且我们规定,以后每个实体类都必须有这个5个基础接口。
所以,当我们再添加一个实体(比如Teacher)时,在TeacherService中也要写和StudentService几乎一样的代码(其实就是把代码里所有“Student”换成“Teacher”就行了)。
这么多重复代码,显然是不符合程序员的审美的。这个时候使用泛型仓储就再适合不过了。
2. 道
整体思路是,写一个基类“BaseService”,这个基类是一个抽象的泛型类,然后让每个实体的Service都继承它。
那么当再新建一个Service时,不需要写任何代码,就已经实现了我们需要的那5种基础CRUD了。
2.1 IService层
在IService层新建一个IBase接口:

using RayPI.Model; namespace RayPI.IService { public interface IBase<T> where T:class,new() { /// <summary> /// 获取分页列表 /// </summary> /// <param name="pageIndex"></param> /// <param name="pageSize"></param> /// <returns></returns> TableModel<T> GetPageList(int pageIndex, int pageSize); /// <summary> /// 获取单个 /// </summary> /// <param name="id"></param> /// <returns></returns> T Get(long id); /// <summary> /// 添加 /// </summary> /// <param name="entity"></param> /// <returns></returns> bool Add(T entity); /// <summary> /// 编辑 /// </summary> /// <param name="entity"></param> /// <returns></returns> bool Update(T entity); /// <summary> /// 批量删除 /// </summary> /// <param name="ids"></param> /// <returns></returns> bool Dels(dynamic[] ids); } }
该接口是个泛型接口,里面集成了对泛型T的5中基础CRUD操作。
2.2 Service层
在Service层新建一个BaseService类:

using RayPI.Model; using SqlSugar; using System; using System.Collections.Generic; using System.Linq; using System.Linq.Expressions; using System.Text; namespace RayPI.Service { /// <summary> /// 服务层基类 /// </summary> /// <typeparam name="T"></typeparam> public abstract class BaseService<T> where T:class,new() { public BaseService() { db = GetClient(); sdb = db.GetSimpleClient(); } public SqlSugarClient db; public SimpleClient sdb; /// <summary> /// 获取客户端 /// </summary> /// <returns></returns> private SqlSugarClient GetClient() { SqlSugarClient db = new SqlSugarClient( new ConnectionConfig() { ConnectionString = BaseDBConfig.ConnectionString, DbType = DbType.SqlServer, IsAutoCloseConnection = true } ); db.Aop.OnLogExecuting = (sql, pars) => { Console.WriteLine(sql + "\r\n" + db.Utilities.SerializeObject(pars.ToDictionary(it => it.ParameterName, it => it.Value))); Console.WriteLine(); }; return db; } #region CRUD public TableModel<T> GetPageList(int pageIndex, int pageSize) { PageModel p = new PageModel() { PageIndex = pageIndex, PageSize = pageSize }; Expression<Func<T, bool>> ex = (it => 1 == 1); List<T> data = sdb.GetPageList(ex, p); var t = new TableModel<T> { Code = 0, Count = p.PageCount, Data = data, Msg = "成功" }; return t; } public T Get(long id) { return sdb.GetById<T>(id); } public bool Add(T entity) { return sdb.Insert(entity); } public bool Update(T entity) { return sdb.Update(entity); } public bool Dels(dynamic[] ids) { return sdb.DeleteByIds<T>(ids); } #endregion } }
该类为abstract抽象类,只能用来被其他类继承,不能实例化。
然后该类除了之前的获取SqlSugarClient的函数,还了5个集成基础CRUD操作,不一样的是这里不是传的实体类,而是一个泛型T。
3. 果
下面,我们写一个Teacher的完整的增删改查。
先在数据库新建一张教师表:
然后运行项目,调用我们之前写好的自动生成实体类的接口:
生成的实体类是这样的:
在IService层新建一个ITeacher接口:
跟之前不一样的是,这个接口里不需要再写增删改查的接口了,直接继承IBase,把Teacher传过去,就行了。
在Service层,新建一个TeacherService:
该Service也不要写增删改查,直接继承BaseService就有了。
然后Bussiness层和控制器层这里就不说了,跟之前一样:
运行调试:
这样,不用写任何底层仓储,就能实现基础的增删改查了,是不是很爽~
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· Linux系列:如何用 C#调用 C方法造成内存泄露
· AI与.NET技术实操系列(二):开始使用ML.NET
· 记一次.NET内存居高不下排查解决与启示
· 探究高空视频全景AR技术的实现原理
· 理解Rust引用及其生命周期标识(上)
· 阿里最新开源QwQ-32B,效果媲美deepseek-r1满血版,部署成本又又又降低了!
· 单线程的Redis速度为什么快?
· SQL Server 2025 AI相关能力初探
· 展开说说关于C#中ORM框架的用法!
· AI编程工具终极对决:字节Trae VS Cursor,谁才是开发者新宠?