十年河东,十年河西,莫欺少年穷
学无止境,精益求精
开发过.NetCore 的都知道,微软的EF框架EFCore对DataTable并不是特别友好,在整个EFCore框架中,直接写SQL语句似乎不太行,因此,在我们的项目中就有必要对数据库操作进行扩展。
自上篇博客 netCore 引用第三方ORM中间件-Dapper 后,我在项目架构时将Dapper引入到数据库操作层,使用后,我发现Dapper对 IQueryable 的支持几乎没有,【也可能有,但是我没发现】,这对于追求性能的开发人员来说难以接受,因此,今天引入sqlSugar。
Dapper的查询方法:
由上图可知,Dapper 支持IEnumerable ,IEnumerable 和 IQueryable 的区别是前者将数据全部加载到内存,后者是将需要的数据加载到内存。因此,IE比较浪费内存,IQ相对而言是按需开辟内存,因此,我选择IQ,虽说IQ在某些性能方面比不上IE,但现在的系统,大多都是数据量庞大的。
现在进入正题,sqlSugar的搭建。
俗话说:工欲善其事必先利其器,因此,在项目搭建之前,我们需要准备一个小的数据库。
简单的数据库,只有两张表,
1、打开VS,新建一个netCore3.1的控制台程序,并新增两个类库,如下:
2、SugarEntity为实体层,实体层代码有项目或工具生成,当然,也可以手写。注:需要引入:SqlASugar V 5.0.0.19 版本。
SugarContext为数据上下文层,用于操作数据库,代码也可以通过项目或工具生成,当然,也可以手写。注:需要引入:SqlASugar V 5.0.0.19 版本 和 Newtonsoft.Json V 12.0.3 及 System.Data.SqlClient V 4.8.2 版本
SugarCore为控制台输出层,需要引入SqlASugar V 5.0.0.19 版本
关于上述的【可通过项目/工具生成】大家可参考:http://www.codeisbug.com/Doc/8/1123 或者 直接去CSDN 上下载相关工具/项目:https://download.csdn.net/download/wolongbb/12997789
这里,将代码生成工具截图如下:
工具仅能生成实体类,并不能生成上下文层
重要的话,再说一遍,不管是那一层,我们都可以通过手动写代码的形式实现
3、更层次代码:
3.1、实体层Entity代码如下
Student 实体层
using System; using System.Linq; using System.Text; using SqlSugar; namespace Sugar.Enties { ///<summary> /// ///</summary> [SugarTable("Student")] public partial class Student { public Student(){ } /// <summary> /// Desc: /// Default: /// Nullable:False /// </summary> [SugarColumn(IsPrimaryKey=true)] public string StudentID {get;set;} /// <summary> /// Desc: /// Default: /// Nullable:True /// </summary> public string GradID {get;set;} /// <summary> /// Desc: /// Default: /// Nullable:True /// </summary> public string StudentName {get;set;} /// <summary> /// Desc: /// Default: /// Nullable:True /// </summary> public string StudentSex {get;set;} /// <summary> /// Desc: /// Default: /// Nullable:True /// </summary> public DateTime? CreateTime {get;set;} } }
StudentGrad 实体层
using System; using System.Linq; using System.Text; using SqlSugar; namespace Sugar.Enties { ///<summary> /// ///</summary> [SugarTable("StudentGrad")] public partial class StudentGrad { public StudentGrad(){ } /// <summary> /// Desc: /// Default: /// Nullable:False /// </summary> [SugarColumn(IsPrimaryKey=true)] public string GradID {get;set;} /// <summary> /// Desc: /// Default: /// Nullable:True /// </summary> public string GradName {get;set;} /// <summary> /// Desc: /// Default: /// Nullable:True /// </summary> public DateTime? CreateTime {get;set;} } }
3.2、上下文层代码如下:
public class SugarDbContext { public SugarDbContext() { Db = new SqlSugarClient(new ConnectionConfig() { ConnectionString = "Data Source=LAPTOP-P5GVS4UM;Initial Catalog=StudentDB;Integrated Security=True", DbType = DbType.SqlServer, InitKeyType = InitKeyType.Attribute,//从特性读取主键和自增列信息 IsAutoCloseConnection = true,//开启自动释放模式和EF原理一样我就不多解释了 }); //调式代码 用来打印SQL Db.Aop.OnLogExecuting = (sql, pars) => { Console.WriteLine(sql + " " + Db.Utilities.SerializeObject(pars.ToDictionary(it => it.ParameterName, it => it.Value))); Console.WriteLine(); }; } //注意:不能写成静态的 public SqlSugarClient Db;//用来处理事务多表查询和复杂的操作 }
及
using SqlSugar; using Sugar.Enties; using System; using System.Collections.Generic; using System.Linq; using System.Linq.Expressions; namespace SugarContext { public class SugarDbContext<T> where T : class, new() { public SugarDbContext() { Db = new SqlSugarClient(new ConnectionConfig() { ConnectionString = "Data Source=LAPTOP-P5GVS4UM;Initial Catalog=StudentDB;Integrated Security=True", DbType = DbType.SqlServer, InitKeyType = InitKeyType.Attribute,//从特性读取主键和自增列信息 IsAutoCloseConnection = true,//开启自动释放模式和EF原理一样我就不多解释了 }); //调式代码 用来打印SQL Db.Aop.OnLogExecuting = (sql, pars) => { Console.WriteLine(sql + " " + Db.Utilities.SerializeObject(pars.ToDictionary(it => it.ParameterName, it => it.Value))); Console.WriteLine(); }; } //注意:不能写成静态的 public SqlSugarClient Db;//用来处理事务多表查询和复杂的操作 public SimpleClient<T> CurrentDb { get { return new SimpleClient<T>(Db); } }//用来操作当前表的数据 public SimpleClient<StudentGrad> StudentGradDb { get { return new SimpleClient<StudentGrad>(Db); } }//用来处理StudentGrad表的常用操作 public SimpleClient<Student> StudentDb { get { return new SimpleClient<Student>(Db); } }//用来处理Student表的常用操作 /// <summary> /// 获取所有 /// </summary> /// <returns></returns> public virtual List<T> GetList() { return CurrentDb.GetList(); } /// <summary> /// 根据表达式查询 /// </summary> /// <returns></returns> public virtual List<T> GetList(Expression<Func<T, bool>> whereExpression) { return CurrentDb.GetList(whereExpression); } /// <summary> /// 根据表达式查询分页 /// </summary> /// <returns></returns> public virtual List<T> GetPageList(Expression<Func<T, bool>> whereExpression, PageModel pageModel) { return CurrentDb.GetPageList(whereExpression, pageModel); } /// <summary> /// 根据表达式查询分页并排序 /// </summary> /// <param name="whereExpression">it</param> /// <param name="pageModel"></param> /// <param name="orderByExpression">it=>it.id或者it=>new{it.id,it.name}</param> /// <param name="orderByType">OrderByType.Desc</param> /// <returns></returns> public virtual List<T> GetPageList(Expression<Func<T, bool>> whereExpression, PageModel pageModel, Expression<Func<T, object>> orderByExpression = null, OrderByType orderByType = OrderByType.Asc) { return CurrentDb.GetPageList(whereExpression, pageModel, orderByExpression, orderByType); } /// <summary> /// 根据主键查询 /// </summary> /// <returns></returns> public virtual T GetById(dynamic id) { return CurrentDb.GetById(id); } /// <summary> /// 根据主键删除 /// </summary> /// <param name="id"></param> /// <returns></returns> public virtual bool Delete(dynamic id) { return CurrentDb.Delete(id); } /// <summary> /// 根据实体删除 /// </summary> /// <param name="id"></param> /// <returns></returns> public virtual bool Delete(T data) { return CurrentDb.Delete(data); } /// <summary> /// 根据主键删除 /// </summary> /// <param name="id"></param> /// <returns></returns> public virtual bool Delete(dynamic[] ids) { return CurrentDb.AsDeleteable().In(ids).ExecuteCommand() > 0; } /// <summary> /// 根据表达式删除 /// </summary> /// <param name="id"></param> /// <returns></returns> public virtual bool Delete(Expression<Func<T, bool>> whereExpression) { return CurrentDb.Delete(whereExpression); } /// <summary> /// 根据实体更新,实体需要有主键 /// </summary> /// <param name="id"></param> /// <returns></returns> public virtual bool Update(T obj) { return CurrentDb.Update(obj); } /// <summary> ///批量更新 /// </summary> /// <param name="id"></param> /// <returns></returns> public virtual bool Update(List<T> objs) { return CurrentDb.UpdateRange(objs); } /// <summary> /// 插入 /// </summary> /// <param name="id"></param> /// <returns></returns> public virtual bool Insert(T obj) { return CurrentDb.Insert(obj); } /// <summary> /// 批量 /// </summary> /// <param name="id"></param> /// <returns></returns> public virtual bool Insert(List<T> objs) { return CurrentDb.InsertRange(objs); } //自已扩展更多方法 } }
3.3、首先,我们创建一百万条数据,方便今天的测试。
在这里,使用了下面的随机姓名方法,每次会产生151302条数据,我们执行7次以上,数据即可达到百万级。
插入代码如下:
最终数据量为120万条数据,如下:
3.4、测试代码如下:
using SqlSugar; using Sugar.Enties; using SugarContext; using System; namespace SugarCore { class Program { static void Main(string[] args) { SugarDbContext<Student> db = new SugarDbContext<Student>(); var Lst_Qb = db.Db.Queryable<Student>().ToList(); var lst = db.GetList(); var list = db.Db.Queryable<Student, StudentGrad>((st, sc) => new object[] { JoinType.Inner,st.GradID==sc.GradID}) .Select<ViewModel>().ToList(); foreach (var item in list) { Console.WriteLine(item.GradName + item.StudentName); } Console.ReadLine(); } } class ViewModel { public string StudentID { get; set; } public string GradID { get; set; } public string StudentName { get; set; } public string StudentSex { get; set; } public DateTime? CreateTime { get; set; } public string GradName { get; set; } } }
输出结果为:
由上图可知,使用SqlSugar 框架时,Context层可以直接记录执行的SQL语句。
以上便是整个Sugar项目的搭建,当然,这都是基础demo,现在说说通过项目来生成数据库上下文层及实体层。
通过上述CSDN 可以下载到该项目
:
项目中有生成步骤的详细说明,摘抄如下:
### SoEasyPlatform 代码生成器 ## 介绍 一款轻量级开源的代码生成器,相对较动软代码生成器而言要轻量的多,支持多种数据库,所用到dll组件也都在github有源码,代码非常的简单有点基础的看源码可以把生成的项目改成自已的风格。 ## 特色 该代码生成器最大的特点就三个简单 ,无需安装,生成的代码 简单并且有教学用例,还有就是调试和修改模版简单。 ## 使用步骤 1.从上面的地址下载 SoEasyPlatform到本地 2.解压项目 点击SoEasyPlatform.sln打开项目,重新生成项目会自动下载NUGET 文件 3.配置三个参数 const SqlSugar.DbType dbType = DbType.SqlServer;//数据库类型 const string connectionString = "server=.;uid=sa;pwd=@jhl85661501;database=SqlSugar4XTest";//连接字符串 const string SolutionName = "SoEasyPlatform";//解决方案名称 4.F5运行 5.完成 我们发现两个类库已经添加到解决方案下面了,并且相关的dll的类库引用也帮我们做好了,非常方便,数据库有改动后F5刷新就好了。 执行完成没发现有类库加进来,关掉解决方案重新打开便可以了 ## 如何使用生成的代码开发项目 1.新建一个项目 Web项目或者控制台都可以 2.引用生成的类库 3.代码如下 StudentManager m = new StudentManager();
关于Sugar的性能,直接看官方文档即可,据说比EF好的多,比Dapper也要好的多。
插入比赛:
更新比赛:
查询比赛:
SqlSugar通过项目生成的代码中提供了相当丰富的学习方法【】,其友好态度值得一赞,现将方法贴出来,供大家参考:
#region 教学方法 /// <summary> /// 如果DbContext中的增删查改方法满足不了你,你可以看下具体用法 /// </summary> public void Study() { /*********查询*********/ var data1 = StudentGradDb.GetById(1);//根据ID查询 var data2 = StudentGradDb.GetList();//查询所有 var data3 = StudentGradDb.GetList(it => 1 == 1); //根据条件查询 //var data4 = StudentGradDb.GetSingle(it => 1 == 1);//根据条件查询一条,如果超过一条会报错 var p = new PageModel() { PageIndex = 1, PageSize = 2 };// 分页查询 var data5 = StudentGradDb.GetPageList(it => 1 == 1, p); Console.Write(p.PageCount);//返回总数 var data6 = StudentGradDb.GetPageList(it => 1 == 1, p, it => SqlFunc.GetRandom(), OrderByType.Asc);// 分页查询加排序 Console.Write(p.PageCount);//返回总数 List<IConditionalModel> conModels = new List<IConditionalModel>(); //组装条件查询作为条件实现 分页查询加排序 conModels.Add(new ConditionalModel() { FieldName = typeof(StudentGrad).GetProperties()[0].Name, ConditionalType = ConditionalType.Equal, FieldValue = "1" });//id=1 var data7 = StudentGradDb.GetPageList(conModels, p, it => SqlFunc.GetRandom(), OrderByType.Asc); StudentGradDb.AsQueryable().Where(x => 1 == 1).ToList();//支持了转换成queryable,我们可以用queryable实现复杂功能 //我要用事务 var result = Db.Ado.UseTran(() => { //写事务代码 }); if (result.IsSuccess) { //事务成功 } //多表查询地址 http://www.codeisbug.com/Doc/8/1124 /*********插入*********/ var insertData = new StudentGrad() { };//测试参数 var insertArray = new StudentGrad[] { insertData }; StudentGradDb.Insert(insertData);//插入 StudentGradDb.InsertRange(insertArray);//批量插入 var id = StudentGradDb.InsertReturnIdentity(insertData);//插入返回自增列 StudentGradDb.AsInsertable(insertData).ExecuteCommand();//我们可以转成 Insertable实现复杂插入 /*********更新*********/ var updateData = new StudentGrad() { };//测试参数 var updateArray = new StudentGrad[] { updateData };//测试参数 StudentGradDb.Update(updateData);//根据实体更新 StudentGradDb.UpdateRange(updateArray);//批量更新 //StudentGradDb.Update(it => new StudentGrad() { Name = "a", CreateTime = DateTime.Now }, it => it.id==1);// 只更新Name列和CreateTime列,其它列不更新,条件id=1 StudentGradDb.AsUpdateable(updateData).ExecuteCommand(); /*********删除*********/ var deldata = new StudentGrad() { };//测试参数 StudentGradDb.Delete(deldata);//根据实体删除 StudentGradDb.DeleteById(1);//根据主键删除 StudentGradDb.DeleteById(new int[] { 1,2});//根据主键数组删除 StudentGradDb.Delete(it=>1==2);//根据条件删除 StudentGradDb.AsDeleteable().Where(it=>1==2).ExecuteCommand();//转成Deleteable实现复杂的操作 } #endregion
等等吧,总之SqlSugar人性化的设计 加 优良的性能赢得了我的心。
爱你, SqlSugar
@天才卧龙的博客