net core Webapi基础工程搭建(六)——数据库操作_Part 1
前言
后端开发最常打交道的就是数据库了(静态网站靠边),上一篇net core Webapi基础工程搭建(五)——缓存机制,缓存就是为了减少数据库的读操作,不过什么访问都是会耗时的,拿空间(内存)换时间对用户体验来说是惯用手段,后续介绍界面操作的时候再说用户体验。
SqlSugar
当然你可以用EF(太重,扩展性相对差,但不可否认基本上涵盖范围够广),也可以用Dapper(这个我之前头一回鼓捣net core的时候用的是Dapper),或者自己基于原生去写数据库的操作,都Ok,但是如果有造好的轮子,对于我们来说用就行了,可以深入理解但对于常规开发来说,CV大法是最好的(新手向),SqlSugar的文档地址。
之前的工程在最初创建的时候,没有创建完整,因为当时不操作数据层,所以偷个懒,这次一并创建,具体过程不再赘述
,同April.Util工程的创建一致,都是类库项目,新建April.Service,April.Entity。
好了,我们在Service与Entity项目中通过NuGet包引入sqlSugarCore,至于原因前面也说过net core Webapi基础工程搭建(四)——日志功能log4net。
这里应该不需要再图文介绍引入了,如果不清楚,也可以去上面的链接查看NuGet的引入方法。
引入完成后,我们在Entity项目创建一个类对象,命名为StudentEntity吧,只是做个示例。
public class StudentEntity
{
private int _ID = -1;
private string _Name = string.Empty;
private string _Number = string.Empty;
private int _Age = 0;
private int _Sex = 0;
private string _Address = string.Empty;
}
对象属性这块儿,看个人习惯,有些人偏向于直接get,set方法,我习惯于先初始化,选中所有的私有属性,使用宇宙第一IDE的快捷键Ctrl+R+E,点击确定,好了自己去加注释去吧。
这里也说下为什么Entity这个实例对象层也要引入SqlSugar,是因为如果你的表名或者属性名与数据库不一致的时候,还是需要标识出来的,比如下面的代码,具体的用法还是去参考文档吧,我这只是轻描淡写下。
[SugarTable("test_Student")]
public class StudentEntity
{
private int _ID = -1;
private string _Name = string.Empty;
private string _Number = string.Empty;
private int _Age = 0;
private int _Sex = 0;
private string _Address = string.Empty;
/// <summary>
/// 主键
/// </summary>
[SugarColumn(IsPrimaryKey = true, IsIdentity = true)]
public int ID { get => _ID; set => _ID = value; }
/// <summary>
/// 姓名
/// </summary>
public string Name { get => _Name; set => _Name = value; }
/// <summary>
/// 学号
/// </summary>
public string Number { get => _Number; set => _Number = value; }
/// <summary>
/// 年龄
/// </summary>
public int Age { get => _Age; set => _Age = value; }
/// <summary>
/// 性别
/// </summary>
public int Sex { get => _Sex; set => _Sex = value; }
/// <summary>
/// 家庭住址
/// </summary>
[SugarColumn(ColumnName = "test_Address")]
public string Address { get => _Address; set => _Address = value; }
}
实体对象我就不多写了,重复的工作是根据你自己的业务所处理的。
Service层
这个地方我重点标注下,是因为数据库这块儿的操作还是需要重视的,我们先来新建个BaseDbContext用于执行数据库操作的实体。
public class BaseDbContext
{
public SqlSugarClient Db;
/// <summary>
/// 构造函数
/// </summary>
/// <param name="connStr">数据库连接串</param>
/// <param name="sqlType">数据库类型</param>
public BaseDbContext(string connStr, int sqlType = 1)
{
InitDataBase(connStr, sqlType);
}
/// <summary>
/// 构造函数
/// </summary>
/// <param name="serverIp">服务器IP</param>
/// <param name="user">用户名</param>
/// <param name="pass">密码</param>
/// <param name="dataBase">数据库</param>
public BaseDbContext(string serverIp, string user, string pass, string dataBase)
{
string connStr = $"server={serverIp};user id={user};password={pass};persistsecurityinfo=True;database={dataBase}";
InitDataBase(connStr);
}
/// <summary>
/// 初始化数据库连接
/// </summary>
/// <param name="listConn">连接字符串</param>
private void InitDataBase(string connStr, int sqlType = 1)
{
Db = new SqlSugarClient(new ConnectionConfig()
{
ConnectionString = connStr,
DbType = (DbType)sqlType,
IsAutoCloseConnection = true,
//SlaveConnectionConfigs = slaveConnectionConfigs
});
Db.Ado.CommandTimeOut = 30000;//设置超时时间
Db.Aop.OnLogExecuted = (sql, pars) => //SQL执行完事件
{
//这里可以查看执行的sql语句跟参数
};
Db.Aop.OnLogExecuting = (sql, pars) => //SQL执行前事件
{
//这里可以查看执行的sql语句跟参数
};
Db.Aop.OnError = (exp) =>//执行SQL 错误事件
{
//这里可以查看执行的sql语句跟参数
};
Db.Aop.OnExecutingChangeSql = (sql, pars) => //SQL执行前 可以修改SQL
{
return new KeyValuePair<string, SugarParameter[]>(sql, pars);
};
}
/// <summary>
/// 开启事务
/// </summary>
public void BeginTran()
{
Db.Ado.BeginTran();
}
/// <summary>
/// 提交事务
/// </summary>
public void CommitTran()
{
Db.Ado.CommitTran();
}
/// <summary>
/// 回滚事务
/// </summary>
public void RollbackTran()
{
Db.Ado.RollbackTran();
}
}
构造函数主要用于实例化你的数据库对象(连接串,数据库类型),日志的记录,事务这些也都标注上,后续可以替换直接使用。
BaseService(基类)
在最初写net core的时候,我用Repository层来实现sql处理,Service用来做逻辑处理,传统的三层架构,但是对于简单的工程来说,个人感觉Bll层的存在不是那么理想,可能是我没彻底理解三层架构吧,这个地方如果有个人想法或好的见解也希望一块交流,互相进步。
在写基类之前,我们在Util层新建一个SqlSqlFilterEntity,这步可能算是多此一举,但是为了减少团队其他人的学习成本,我还是写了这个对象,以致于后续的封装,会以此为参数做传递而不公开lambda的写法使用。
public class SqlFilterEntity
{
private string _Filter = string.Empty;
private Dictionary<string, object> _Value = null;
/// <summary>
/// 查询条件
/// </summary>
public string Filter { get => _Filter; set => _Filter = value; }
/// <summary>
/// 查询参数
/// </summary>
public Dictionary<string, object> Value { get => _Value; set => _Value = value; }
}
在Service层新建IBaseService接口。
public interface IBaseService<T> : IDisposable
{
/// <summary>
/// 分页查询集合
/// </summary>
/// <param name="pageIndex">页码</param>
/// <param name="pageSize">分页大小</param>
/// <param name="strField">查询字段</param>
/// <param name="filter">查询条件</param>
/// <param name="strOrder">排序规则</param>
/// <param name="totalCount">总数</param>
/// <returns>数据集合</returns>
List<T> GetPageList(int pageIndex, int pageSize, string strField, SqlFilterEntity filter, string strOrder, out int totalCount);
/// <summary>
/// 获取列表集合
/// </summary>
/// <param name="field">查询字段</param>
/// <param name="filter">查询条件</param>
/// <returns>数据集合</returns>
ISugarQueryable<T> GetList(string field, SqlFilterEntity filter);
/// <summary>
/// 获取列表集合
/// </summary>
/// <returns>数据集合</returns>
ISugarQueryable<T> GetList(int top = 0);
/// <summary>
/// 获取对象
/// </summary>
/// <param name="field">查询字段</param>
/// <param name="filter">查询条件</param>
/// <returns>对象</returns>
T GetEntity(SqlFilterEntity filter, string field = "");
/// <summary>
/// 判断数据是否存在
/// </summary>
/// <param name="filter">查询条件</param>
/// <returns>执行结果</returns>
bool IsExists(SqlFilterEntity filter);
/// <summary>
/// 新增
/// </summary>
/// <param name="entity">实例对象</param>
/// <param name="ignoreColumns">排除列</param>
/// <param name="isLock">是否加锁</param>
/// <returns>自增id</returns>
int Insert(T entity, List<string> ignoreColumns = null, bool isLock = false);
/// <summary>
/// 修改
/// </summary>
/// <param name="entity">实例对象</param>
/// <param name="ignoreColumns">排除列</param>
/// <param name="isLock">是否加锁</param>
/// <returns>执行结果</returns>
bool Update(T entity, List<string> ignoreColumns = null, bool isLock = false);
/// <summary>
/// 根据主键删除
/// </summary>
/// <param name="entity">实例对象</param>
/// <param name="isLock">是否加锁</param>
/// <returns>执行结果</returns>
bool Delete(T entity, bool isLock = false);
}
可以看到,我通过SqlFilterEntity这一实例来传递我的Where条件。
实现接口方法,新建BaseService。
public class BaseService<T> : IBaseService<T> where T : class, new()
{
private BaseDbContext baseDb;
protected SqlSugarClient db;
public BaseService()
{
baseDb = new BaseDbContext("你的数据库连接");
db = baseDb.Db;
}
/// <summary>
/// 分页查询集合
/// </summary>
/// <param name="pageIndex">页码</param>
/// <param name="pageSize">分页大小</param>
/// <param name="strField">查询字段</param>
/// <param name="filter">查询条件</param>
/// <param name="strOrder">排序规则</param>
/// <param name="totalCount">总数</param>
/// <returns>数据集合</returns>
public List<T> GetPageList(int pageIndex, int pageSize, string strField, SqlFilterEntity filter, string strOrder, out int totalCount)
{
totalCount = 0;
if (pageIndex <= 0)
{
pageIndex = 1;
}
if (pageSize <= 0)
{
pageSize = 10;//暂定默认分页大小为10
}
if (string.IsNullOrEmpty(strField))
{
strField = "";
}
if (string.IsNullOrEmpty(strOrder))
{
strOrder = string.Format("ID asc");//这个地方我当时是在Config设置默认的排序
}
if (filter == null)
{
filter = new SqlFilterEntity();
}
return db.Queryable<T>().With(SqlWith.NoLock).Select(strField).WhereIF(!string.IsNullOrEmpty(filter.Filter), filter.Filter, filter.Value).OrderByIF(!string.IsNullOrEmpty(strOrder), strOrder).ToPageList(pageIndex, pageSize, ref totalCount);
}
/// <summary>
/// 获取列表集合
/// </summary>
/// <param name="field">查询字段</param>
/// <param name="filter">查询条件</param>
/// <returns>数据集合</returns>
public ISugarQueryable<T> GetList(string field, SqlFilterEntity filter)
{
if (string.IsNullOrEmpty(field))
{
field = "";
}
if (filter == null)
{
filter = new SqlFilterEntity();
}
return db.Queryable<T>().With(SqlWith.NoLock).Select(field).WhereIF(!string.IsNullOrEmpty(filter.Filter), filter.Filter, filter.Value);
}
/// <summary>
/// 获取列表集合
/// </summary>
/// <returns>数据集合</returns>
public ISugarQueryable<T> GetList(int top = 0)
{
if (top > 0)
{
return db.Queryable<T>().With(SqlWith.NoLock).Take(top);
}
else
{
return db.Queryable<T>().With(SqlWith.NoLock);
}
}
/// <summary>
/// 获取对象
/// </summary>
/// <param name="field">查询字段</param>
/// <param name="filter">查询条件</param>
/// <returns>对象</returns>
public T GetEntity(SqlFilterEntity filter, string field = "")
{
if (string.IsNullOrEmpty(field))
{
field = "";
}
if (filter != null)
{
return db.Queryable<T>().With(SqlWith.NoLock).Select(field).WhereIF(!string.IsNullOrEmpty(filter.Filter), filter.Filter, filter.Value).First();
}
return default(T);
}
/// <summary>
/// 判断数据是否存在
/// </summary>
/// <param name="filter">查询条件</param>
/// <returns>执行结果</returns>
public bool IsExists(SqlFilterEntity filter)
{
var result = db.Queryable<T>().With(SqlWith.NoLock).WhereIF(!string.IsNullOrEmpty(filter.Filter), filter.Filter, filter.Value).Count();
return result > 0;
}
/// <summary>
/// 新增
/// </summary>
/// <param name="entity">实例对象</param>
/// <param name="ignoreColumns">排除列</param>
/// <param name="isLock">是否加锁</param>
/// <returns>自增id</returns>
public int Insert(T entity, List<string> ignoreColumns = null, bool isLock = false)
{
if (ignoreColumns == null)
{
ignoreColumns = new List<string>();
}
var result = isLock ?
db.Insertable(entity).With(SqlWith.UpdLock).IgnoreColumns(ignoreColumns.ToArray()).ExecuteReturnIdentity()
: db.Insertable(entity).IgnoreColumns(ignoreColumns.ToArray()).ExecuteReturnIdentity();
return result;
}
/// <summary>
/// 修改
/// </summary>
/// <param name="entity">实例对象</param>
/// <param name="ignoreColumns">排除列</param>
/// <param name="isLock">是否加锁</param>
/// <returns>执行结果</returns>
public bool Update(T entity, List<string> ignoreColumns = null, bool isLock = false)
{
if (ignoreColumns == null)
{
ignoreColumns = new List<string>();
}
var result = isLock ?
db.Updateable(entity).With(SqlWith.UpdLock).IgnoreColumns(ignoreColumns.ToArray()).ExecuteCommand()
: db.Updateable(entity).IgnoreColumns(ignoreColumns.ToArray()).ExecuteCommand();
return result > 0;
}
/// <summary>
/// 根据主键删除
/// </summary>
/// <param name="entity">实例对象</param>
/// <param name="isLock">是否加锁</param>
/// <returns>执行结果</returns>
public bool Delete(T entity, bool isLock = false)
{
var result = isLock ?
db.Deleteable<T>(entity).With(SqlWith.RowLock).ExecuteCommand().ObjToBool()
: db.Deleteable<T>(entity).ExecuteCommand().ObjToBool();
return result;
}
public void Dispose()
{
}
}
小结
这一篇感觉写的不多,但是代码放的有点儿多,习惯性的把东西尽可能介绍详细点儿,万一有人真的从小白开始一点点儿想折腾个啥东西呢(比如说我),下一篇Part 2介绍具体的用法和测试吧。
net core Webapi基础工程搭建(六)——数据库操作_Part 1的更多相关文章
- net core Webapi基础工程搭建(六)——数据库操作_Part 2
目录 前言 开始 使用 小结 前言 昨天是写着写着发现,时间不早了,已经养成了晚上下班抽时间看看能写点儿啥的习惯(貌似),今天实在是不想让昨天没做完的事情影响,所以又坐下,沉下心(周末了),开始把数据 ...
- net core Webapi基础工程搭建(七)——小试AOP及常规测试_Part 2
目录 前言 引入 自定义属性 测试 小结 前言 前一篇讲到了中间层的使用,可能不是那么AOP,今天主要来说下一个轻量级的AOP第三方类库AspectoCore. 简单介绍下这个类库,AspectCor ...
- net core Webapi基础工程搭建(五)——缓存机制
目录 前言 Cache Session Cookie 小结 补充 前言 作为WebApi接口工程,性能效率是必不可少的,每次的访问请求,数据库读取,业务逻辑处理都或多或少耗费时间,偶尔再来个各种花式f ...
- net core Webapi基础工程搭建(二)——创建工程
目录 前言 创建工程 工程文件概述(个人理解) 运行 小结 前言 前面介绍了开发工具及net core版本,后端工程的框架结构开发工具及环境,因为是基础工程,所以没考虑太复杂的框架,如果有架构师请勿喷 ...
- net core Webapi基础工程搭建(七)——小试AOP及常规测试_Part 1
目录 前言 拦截器 异常拦截器 测试结果 身份验证拦截器 测试 小结 补充 2019-07-31 前言 一天天不知道怎么过的,但确实挺忙,事赶事不带停那种,让我感觉跟在流水线干活一样,忙活的事差不多了 ...
- net core Webapi基础工程搭建(一)——开发工具及环境
目录 开发工具 版本 后端框架 开发工具 Visual Studio 2019,既然要折腾那就体验最新版的开发工具有什么特殊的地方,之前个人开发使用的是2017. 下载地址:https://visua ...
- net core Webapi基础工程搭建(四)——日志功能log4net
目录 前言 log4net 依然是,NuGet引用第三方类库 整合LogUtil 小结 前言 一个完整的项目工程离不开日志文件的记录,而记录文件的方法也有很多,可以自己通过Stream去实现文件的读写 ...
- net core Webapi基础工程搭建(三)——在线接口文档Swagger
目录 前言 Swagger NuGet引用第三方类库 别急,还有 没错,注释 小结 前言 前后分离的好处,就是后端埋头做业务逻辑功能,不需要过多考虑用户体验,只专注于数据.性能开发,对于前端需要的数据 ...
- 第十九节:Asp.Net Core WebApi基础总结和请求方式
一. 基础总结 1.Restful服务改造 Core下的WebApi默认也是Restful格式服务,即通过请求方式(Get,post,put,delete)来区分请求哪个方法,请求的URL中不需要写方 ...
随机推荐
- I/O:FileLock
FileLock: /* 文件锁定要么是独占的,要么是共享的.共享锁定可阻止其他并发运行的程序获取重叠的 独占锁定,但是允许该程序获取重叠的共享锁定.独占锁定则阻止其他程序获取任一类型的重叠锁 定.一 ...
- ASP.NET 前端数据绑定---<%#%>及Eval()的使用
ASP.NET 前端html代码中会经常出现的<%%>的代码,里面的文本其实就是不能直接输出到客户端浏览器的文本,是需要服务器解释的. 在ASP中,<%%>里面的文本是vbsc ...
- 入职两个月,WPF开发感想
1 .新工作,新开始 2.WPF初次接触以及学习MVVM开发模式 3.后台数据操作,ORACLE 存储过程(边做边学) 4.总结 4.1工作开发中的小问题 ,遇到的坑: 4.2 解决的问题,学校到的 ...
- Excel催化剂100+大主题功能梳理导读
Excel催化剂历经1年4个月的开发时间,终于荣登100+个大主题功能,完成数据领域的功能大矩阵,可以说在日常的数据处理及分析上,绝大部分的共性场景已经囊括其中,是数据工作者难得一遇的优秀作品之一.因 ...
- 盘一盘 synchronized (一)—— 从打印Java对象头说起
Java对象头的组成 Java对象的对象头由 mark word 和 klass pointer 两部分组成, mark word存储了同步状态.标识.hashcode.GC状态等等. klass ...
- java实现线程的两种方式
要求:一个火车站,三个售票员卖出100张票 1.通过继承Thread类实现 实现思路:建立ThreadTest类继承Thread并建立三个线程卖100张票 public class ThreadTes ...
- 微信小程序设计总结
微信小程序是一种全新的连接用户与服务的方式,它可以在微信内被便捷地获取和传播,同时具有出色的使用体验. 小程序提供了一个简单.高效的应用开发框架和丰富的组件及API,帮助开发者在微信中开发具有原生 A ...
- 牛客第十场Rikka with Prefix Sum
由于其中的2操作非常多,我们就需要将其快速的更改,就会用到组合数的东西 其实自己手写一下就可以发现对于一个点增加的值在经过不断地前缀和累加过程中对于一点的贡献满足杨辉三角 所以我们就需要记录一下其中的 ...
- Android的日期选择器
TimePicker(时间选择器) 方法 描述 Integer getCurrentHour () 返回当前设置的小时 Integer getCurrentMinute() 返回当前设置的分钟 boo ...
- jQuery表单校验
主要特性: 表单提交前对所有数据进行校验,不符合不让提交(validate) 如果表单校验不通过,自动focus到第一个错误的域 自动在控件后面显示错误提示内容(error message) 支持根据 ...