十年河東,十年河西,莫欺少年窮
學無止境,精益求精
開發過.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 + "\r\n" + 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 + "\r\n" + 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
@天才卧龍的博客