C# 數據操做系列 - 16 SqlSugar 完結篇

0. 前言

前一篇咱們詳細的介紹了SqlSugar的增刪改查,那些已經知足咱們在平常工程開發中的使用了。可是還有一點點在開發中並不經常使用,可是卻很是有用的方法。接下來讓咱們一塊兒來看看還有哪些有意思的內容。sql

圖片

1. 不一樣尋常的查詢

以前介紹了針對單個表的查詢,一樣也是相對簡單的查詢模式。雖然開發徹底夠用,可是不免會遇到一些特殊的狀況。而下面這些方法就是爲了解決這些意料以外。數據庫

1.1 多表查詢

SqlSugar提供了一種特殊的多表查詢方案,使用IQueryable接口 。來看看是怎樣操做的吧:express

ISugarQueryable<T, T2> Queryable<T, T2>(Expression<Func<T, T2, object[]>> joinExpression);
ISugarQueryable<T, T2> Queryable<T, T2>(ISugarQueryable<T> joinQueryable1, ISugarQueryable<T2> joinQueryable2, Expression<Func<T, T2, bool>> joinExpression)
           where T : class, new()
           where T2 : class, new();
ISugarQueryable<T, T2> Queryable<T, T2>(ISugarQueryable<T> joinQueryable1, ISugarQueryable<T2> joinQueryable2, JoinType joinType, Expression<Func<T, T2, bool>> joinExpression)
           where T : class, new()
           where T2 : class, new();
ISugarQueryable<T, T2> Queryable<T, T2>(Expression<Func<T, T2, bool>> joinExpression) where T : class, new();

這些方法是屬於SqlSugarClient類的方法,SqlSugar提供了最多12個泛型的方法支持,固然實際上開發中能遇到5個表的聯查都不多。除非說是在作報表程序,不然就得審查一下數據表模型是否合理了。就以這四個方法爲例,介紹一下多表查詢如何使用:編程

先來兩個模型類:數組

public class Person
{
   [SugarColumn(IsPrimaryKey = true, IsIdentity = true)]
   public int Id { get; set; }
   public string Name { get; set; }
   public int Age { get; set; }
}
public class Employee
{
   [SugarColumn(IsPrimaryKey = true, IsIdentity = true)]
   public int Id { get; set; }
   public string Name { get; set; }
   public int PersonId { get; set; }
   [SugarColumn(IsIgnore = true)]
   public Person Person { get; set; }
}

簡單的描述一下兩個類的關係:一個僱員身份對應一我的,但一我的不必定會有一個僱員身份。緩存

OK,先從第一個方法提及:app

var query = context.Client.Queryable<Person, Employee>((pr, em)=>new object[]
{
   JoinType.Left,
   em.PersonId == pr.Id
});

第一個返回,是兩個表的鏈接方式,例如:Left表明左鏈接,Inner表示內鏈接,Right表示右鏈接;第二個返回是兩個表之間的鏈接依據。這是一個固定的形式,返回一個Object數組,其中第一個是鏈接方式,第二個是經過哪一個(些)字段進行鏈接。asp.net

生成的SQL相似以下:dom

SELECT `pr`.`Id`,`pr`.`Name`,`pr`.`Age` FROM `Person` pr Left JOIN `Employee` em ON ( `em`.`PersonId` = `pr`.`Id` )

第二個方法:ide

var query = context.Client.Queryable(context.Client.Queryable<Person>(),
               context.Client.Queryable<Employee>(),
               (pr, em) => pr.Id == em.PersonId);

這個方法使用內鏈接鏈接兩個表,最後一個參數用來指定兩個表之間的鏈接字段。

生成的SQL相似以下:

SELECT  `pr`.`Id` AS `Person.Id` , `pr`.`Name` AS `Person.Name` , `pr`.`Age` AS `Person.Age` , `em`.`Id` AS `Employee.Id` , `em`.`Name` AS `Employee.Name` , `em`.`PersonId` AS `Employee.PersonId` , `em`.`DeptId` AS `Employee.DeptId`  FROM  (SELECT `Id`,`Name`,`Age` FROM `Person`  ) pr  Inner JOIN  (SELECT `Id`,`Name`,`PersonId`,`DeptId` FROM `Employee`  ) em   ON ( `pr`.`Id` = `em`.`PersonId` )

第三個方法在第二個方法的基礎上,能夠指定鏈接方式:

var query = context.Client.Queryable(context.Client.Queryable<Person>(),
               context.Client.Queryable<Employee>(),
               JoinType.Left,
               (pr, em) => pr.Id == em.PersonId);

最後一個:

var query = context.Client.Queryable<Person, Employee>((pr, em) => pr.Id == em.PersonId);

直接指定兩個表之間的聯繫方式。

須要指出的是,全部的方法都只是返回了一個可查詢對象,若是不進行後續的投影(進行select)則可能會提示主鍵衝突。並且,全部的方法在進行ToXXX以前都不會當即執行。

1.2 查詢函數

SqlSugar添加了不少咱們經常使用的方法,使其能夠映射爲sql語句。咱們來看一下支持哪些內容:

public class SqlFunc
{
   public static TResult AggregateAvg<TResult>(TResult thisValue);//針對這個列進行取平均數統計
   public static int AggregateCount<TResult>(TResult thisValue);// 統計這個列數量 等價於 SQL裏的 count(x)
   public static int AggregateDistinctCount<TResult>(TResult thisValue);/ 返回去重以後的數量
   public static TResult AggregateMax<TResult>(TResult thisValue);//返回最大值
   public static TResult AggregateMin<TResult>(TResult thisValue);// 返回最小值
   public static TResult AggregateSum<TResult>(TResult thisValue);// 返回總和
   public static bool Between(object value, object start, object end);// 判斷列的值是否在兩個值之間
   public static int CharIndex(string findChar, string searchValue);// SQL 的charindex
   public static bool Contains(string thisValue, string parameterValue);// 是否包含
   public static bool ContainsArray<T>(T[] thisValue, object InField);// 數組是否包含
   public static bool ContainsArray<T>(List<T> thisValue, object InField);//列表蘇菲包含
   public static bool ContainsArrayUseSqlParameters<T>(List<T> thisValue, object InField);//
   public static bool ContainsArrayUseSqlParameters<T>(T[] thisValue, object InField);//
   public static DateTime DateAdd(DateTime date, int addValue, DateType dataType);// 時間添加
   public static DateTime DateAdd(DateTime date, int addValue);// 日期添加
   public static bool DateIsSame(DateTime date1, DateTime date2);// 時間是否相同
   public static bool DateIsSame(DateTime? date1, DateTime? date2);//時間是否相同
   public static bool DateIsSame(DateTime date1, DateTime date2, DateType dataType);//時間是否相同,根據DateType判斷
   public static int DateValue(DateTime date, DateType dataType);// 根據dateType, 返回具體的時間值
   public static bool EndsWith(string thisValue, string parameterValue);//字符串是否以某些值結尾
   public static bool Equals(object thisValue, object parameterValue);//是否相等
   public static DateTime GetDate();//返回當前數據庫時間
   public static string GetRandom();//
   public static TResult GetSelfAndAutoFill<TResult>(TResult value);//
   public static bool HasNumber(object thisValue);//返回是否大於0,且不能爲Null
   public static bool HasValue(object thisValue);// 是否有值,且不爲Null
   public static CaseThen IF(bool condition);// sql 裏的if判斷
   public static TResult IIF<TResult>(bool Expression, TResult thenValue, TResult elseValue);// case when
   public static TResult IsNull<TResult>(TResult thisValue, TResult ifNullValue);// sql 裏的 IsNull
   public static bool IsNullOrEmpty(object thisValue);//判斷是不是Null或者空
   public static int Length(object value);//取長度
   public static TResult MappingColumn<TResult>(TResult oldColumnName, string newColumnName);// 列名映射
   public static string MergeString(string value1, string value2);
   public static string MergeString(string value1, string value2, string value3, string value4);
   public static string MergeString(string value1, string value2, string value3, string value4, string value5);
   public static string MergeString(string value1, string value2, string value3, string value4, string value5, string value6);
   public static string MergeString(string value1, string value2, string value3);
   public static string MergeString(string value1, string value2, string value3, string value4, string value5, string value6, string value7);
   public static string Replace(object value, string oldChar, string newChar);// 替換
   public static bool StartsWith(string thisValue, string parameterValue);
   public static Subqueryable<T> Subqueryable<T>() where T : class, new();
   public static string Substring(object value, int index, int length);// 獲取子串
   public static bool ToBool(object value);//類型轉換
   public static DateTime ToDate(object value);// 類型轉換
   public static decimal ToDecimal(object value);// 類型轉換
   public static double ToDouble(object value);// 類型轉換
   public static Guid ToGuid(object value);// 類型轉換
   public static int ToInt32(object value);// 類型轉換
   public static long ToInt64(object value);// 類型轉換
   public static string ToLower(object thisValue);// 類型轉換
   public static string ToString(object value);// 類型轉換
   public static TimeSpan ToTime(object value);// 類型轉換
   public static string ToUpper(object thisValue);// 類型轉換
   public static string Trim(object thisValue);// 去除首尾的空格
}

這裏的方法大多簡單直接,我就不一一演示了。

1.3 動態查詢

以前咱們寫的查詢條件都是固定好的,至少在編程的時候就知道最終查詢條件是什麼了。可是在開發過程當中,有時候並不會那麼早的知道最終查詢條件或者說查詢須要根據用戶輸入來調整查詢條件,那麼如何實現呢?

常見的解決方案有如下幾種:

  • 使用SQL語句,動態拼接SQL語句,而後根據SQL語句執行返回結果

  • 在使用Lambda表達式時,進行動態拼接Lambda表達式

  • 獲取IQueryable接口,而後根據條件添加方法進行查詢

這三種方法各有優略,使用查詢接口會有一個明顯的問題就是對應用層開放了更高的權限,使用SQL語句也是一樣的道理。因此更符合邏輯的是使用動態拼接Lambda表達式。

固然,SqlSugar在這三種方案之上,提供了另外兩種方案:

正是上一篇文中提到的IConditionalModel和WhereIF。咱們先來看一下IConditionalModel如何使用:

var conditions = new List<IConditionalModel>();
var query = context.Client.Queryable<Person>().Where(conditions);

能夠在Where中傳入IConditionModel類型。SqlSugar提供了兩個受支持的實現類:

public class ConditionalCollections : IConditionalModel
{
   public ConditionalCollections();
   public List<KeyValuePair<WhereType, ConditionalModel>> ConditionalList { get; set; }
}
public class ConditionalModel : IConditionalModel
{
   public ConditionalModel();
   public string FieldName { get; set; }
   public string FieldValue { get; set; }
   public ConditionalType ConditionalType { get; set; }
   public Func<string, object> FieldValueConvertFunc { get; set; }
}

對於一個集合裏的兄弟 ConditionModel,表示查詢條件都是 and 關係。而ConditionCollections則不一樣,其中ConditionList表示是一個鍵值對集合。鍵是WhereType類型,ConditionModel是值。咱們先說說 WhereType:

public enum WhereType
{
   And = 0,
   Or = 1
}

分別表示And,Or。怎樣理解呢?就是說,這一條鍵值對與前一個關係模型是And仍是Or。

看一下示例:

// and id=100 and (id=1 or id=2 and id=1)
conModels.Add(new ConditionalModel() { FieldName = "id", ConditionalType = ConditionalType.Equal, FieldValue = "100" });
conModels.Add(new ConditionalCollections() { ConditionalList=
new List<KeyValuePair<WhereType, SqlSugar.ConditionalModel>>()
{
   new  KeyValuePair<WhereType, ConditionalModel>
   ( WhereType.And ,
   new ConditionalModel() { FieldName = "id", ConditionalType = ConditionalType.Equal, FieldValue = "1" }),
   new  KeyValuePair<WhereType, ConditionalModel>
   (WhereType.Or,
   new ConditionalModel() { FieldName = "id", ConditionalType = ConditionalType.Equal, FieldValue = "2" }),
   new  KeyValuePair<WhereType, ConditionalModel>
   ( WhereType.And,
   new ConditionalModel() { FieldName = "id", ConditionalType = ConditionalType.Equal, FieldValue = "2" })
}
});
var student = db.Queryable<Student>().Where(conModels).ToList();

繼續看一下WhereIF,WhereIF的使用就相對簡單一點:

ISugarQueryable<T> WhereIF(bool isWhere, Expression<Func<T, bool>> expression);

示例代碼:

var query = context.Client.Queryable<Person>().WhereIF(string.IsNullOrEmpty(input), p=>p.Age>10);

理解起來也很容易,第一個參數如何結果爲False,則不執行後續的查詢,不然就執行。

2. 一些高級玩法

除了增刪改查,SqlSugar還提供了一些別的有意思的機制,繼續咱們的探索吧。

2.1 批量操做

SqlSugar提供了一種一次性記錄不少操做而後統一提交執行的模式,以前的操做都是僅支持批量插入、批量修改、批量刪除。在這種模式下,SqlSugar還支持了批量(插入、修改、刪除)。也就是說,在一個批處理中,便可以插入也能夠修改還能夠刪除。

那麼咱們來看如何讓這個功能爲咱們所用吧:

void AddQueue();

在IDeleteable、IInsertable、IUpdateable、ISugarQueryable都有這個方法,一旦調用這個方法就表示該條指令進行緩存不當即執行,直到調用SqlSugarClient.SaveQueues()。經過調用SaveQueues()保存到數據庫中。

值得注意的是:

SqlSugar 雖然支持將查詢也加入到批量操做的支持中,可是這部分在我看來更像是爲了保證接口一致化而做的。我的並不推薦在批處理中加入查詢,由於查詢更多的須要及時準確快速,若是一旦陷入批處理中,查詢就沒法準確快速的返回數據了。

這樣對於設定批處理的初衷,反而是違背的。固然最重要的一點,實際開發中這種狀況不多遇到。

2.2 事務

SQL自己支持事務,大多數ORM都支持事務,SqlSugar也不例外。SqlSugar經過哪些方法來本身實現一個事務呢?

在SqlSugarClient中執行:

public void BeginTran();

會將SqlSugarClient作一個事務標記,表示以後的操做都是在事務中,直到事務提交或者回滾。

在SimpleClient中執行:

public ITenant AsTenant();

返回一個ITenant實例,而後經過這個實例提交事務或者回滾事務。

注意,SqlSugar全部的事務都是針對 SqlSugarClient級別的,也就是說一個事務,一個SqlSugarClient。

2.3 原生SQL執行

SqlSugar在不少地方都添加了原生Sql的支持。

好比說經過以下這種方式,可使用Sql語句進行查詢:

var t12 = context.Client.SqlQueryable<Student>("select * from student").Where(it=>it.id>0).ToPageList(1, 2);

經過如下這種方式,執行SQL:

context.Client.Ado.ExecuteCommand(sql, parameters)

而後,經過如下方式執行存儲過程:

context.Client.Ado.UseStoredProcedure()

3. 總結

優秀的ORM老是有各類各樣的方案,也有各類各樣的優勢。SqlSugar到目前爲止,能夠告一段落了。固然,我仍是剩下了一部分,留給大夥本身去探索挖掘。接下來,我將以Dapper做爲《C# 數據操做系列》的最後內容。以後將會以項目的形式,帶領你們去了解並學習asp.net core。

相關文章
相關標籤/搜索