时间:2020-7-8来源:本站原创作者:佚名
中药白癜风的治疗方法 http://m.39.net/pf/a_5060463.html
0.前言

前一篇我们详细的介绍了SqlSugar的增删改查,那些已经满足我们在日常工程开发中的使用了。但是还有一点点在开发中并不常用,但是却非常有用的方法。接下来让我们一起来看看还有哪些有意思的内容。

1.不同寻常的查询

之前介绍了针对单个表的查询,同样也是相对简单的查询模式。虽然开发完全够用,但是难免会遇到一些特殊的情况。而下面这些方法就是为了解决这些意料之外。

1.1多表查询

SqlSugar提供了一种特殊的多表查询方案,使用IQueryable接口。来看看是怎样操作的吧:

ISugarQueryableT,T2QueryableT,T2(ExpressionFuncT,T2,object[]joinExpression);ISugarQueryableT,T2QueryableT,T2(ISugarQueryableTjoinQueryable1,ISugarQueryableT2joinQueryable2,ExpressionFuncT,T2,booljoinExpression)whereT:class,new()whereT2:class,new();ISugarQueryableT,T2QueryableT,T2(ISugarQueryableTjoinQueryable1,ISugarQueryableT2joinQueryable2,JoinTypejoinType,ExpressionFuncT,T2,booljoinExpression)whereT:class,new()whereT2:class,new();ISugarQueryableT,T2QueryableT,T2(ExpressionFuncT,T2,booljoinExpression)whereT:class,new();

这些方法是属于SqlSugarClient类的方法,SqlSugar提供了最多12个泛型的方法支持,当然实际上开发中能遇到5个表的联查都很少。除非说是在做报表程序,否则就得审查一下数据表模型是否合理了。就以这四个方法为例,介绍一下多表查询如何使用:

先来两个模型类:

publicclassPerson{[SugarColumn(IsPrimaryKey=true,IsIdentity=true)]publicintId{get;set;}publicstringName{get;set;}publicintAge{get;set;}}publicclassEmployee{[SugarColumn(IsPrimaryKey=true,IsIdentity=true)]publicintId{get;set;}publicstringName{get;set;}publicintPersonId{get;set;}[SugarColumn(IsIgnore=true)]publicPersonPerson{get;set;}}

简单的描述一下两个类的关系:一个雇员身份对应一个人,但一个人不一定会有一个雇员身份。

OK,先从第一个方法说起:

varquery=context.Client.QueryablePerson,Employee((pr,em)=newobject[]{JoinType.Left,em.PersonId==pr.Id});

第一个返回,是两个表的连接方式,例如:Left代表左连接,Inner表示内连接,Right表示右连接;第二个返回是两个表之间的连接依据。这是一个固定的形式,返回一个Object数组,其中第一个是连接方式,第二个是通过哪个(些)字段进行连接。

生成的SQL类似如下:

SELECT`pr`.`Id`,`pr`.`Name`,`pr`.`Age`FROM`Person`prLeftJOIN`Employee`emON(`em`.`PersonId`=`pr`.`Id`)

第二个方法:

varquery=context.Client.Queryable(context.Client.QueryablePerson(),context.Client.QueryableEmployee(),(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`)prInnerJOIN(SELECT`Id`,`Name`,`PersonId`,`DeptId`FROM`Employee`)emON(`pr`.`Id`=`em`.`PersonId`)

第三个方法在第二个方法的基础上,可以指定连接方式:

varquery=context.Client.Queryable(context.Client.QueryablePerson(),context.Client.QueryableEmployee(),JoinType.Left,(pr,em)=pr.Id==em.PersonId);

最后一个:

varquery=context.Client.QueryablePerson,Employee((pr,em)=pr.Id==em.PersonId);

直接指定两个表之间的联系方式。

需要指出的是,所有的方法都只是返回了一个可查询对象,如果不进行后续的投影(进行select)则可能会提示主键冲突。而且,所有的方法在进行ToXXX之前都不会立即执行。

1.2查询函数

SqlSugar添加了很多我们常用的方法,使其可以映射为sql语句。我们来看一下支持哪些内容:

publicclassSqlFunc{publicstaticTResultAggregateAvgTResult(TResultthisValue);//针对这个列进行取平均数统计publicstaticintAggregateCountTResult(TResultthisValue);//统计这个列数量等价于SQL里的count(x)publicstaticintAggregateDistinctCountTResult(TResultthisValue);/返回去重之后的数量publicstaticTResultAggregateMaxTResult(TResultthisValue);//返回最大值publicstaticTResultAggregateMinTResult(TResultthisValue);//返回最小值publicstaticTResultAggregateSumTResult(TResultthisValue);//返回总和publicstaticboolBetween(objectvalue,objectstart,objectend);//判断列的值是否在两个值之间publicstaticintCharIndex(stringfindChar,stringsearchValue);//SQL的charindexpublicstaticboolContains(stringthisValue,stringparameterValue);//是否包含publicstaticboolContainsArrayT(T[]thisValue,objectInField);//数组是否包含publicstaticboolContainsArrayT(ListTthisValue,objectInField);//列表苏菲包含publicstaticboolContainsArrayUseSqlParametersT(ListTthisValue,objectInField);//publicstaticboolContainsArrayUseSqlParametersT(T[]thisValue,objectInField);//publicstaticDateTimeDateAdd(DateTimedate,intaddValue,DateTypedataType);//时间添加publicstaticDateTimeDateAdd(DateTimedate,intaddValue);//日期添加publicstaticboolDateIsSame(DateTimedate1,DateTimedate2);//时间是否相同publicstaticboolDateIsSame(DateTime?date1,DateTime?date2);//时间是否相同publicstaticboolDateIsSame(DateTimedate1,DateTimedate2,DateTypedataType);//时间是否相同,根据DateType判断publicstaticintDateValue(DateTimedate,DateTypedataType);//根据dateType,返回具体的时间值publicstaticboolEndsWith(stringthisValue,stringparameterValue);//字符串是否以某些值结尾publicstaticboolEquals(objectthisValue,objectparameterValue);//是否相等publicstaticDateTimeGetDate();//返回当前数据库时间publicstaticstringGetRandom();//publicstaticTResultGetSelfAndAutoFillTResult(TResultvalue);//publicstaticboolHasNumber(objectthisValue);//返回是否大于0,且不能为NullpublicstaticboolHasValue(objectthisValue);//是否有值,且不为NullpublicstaticCaseThenIF(boolcondition);//sql里的if判断publicstaticTResultIIFTResult(boolExpression,TResultthenValue,TResultelseValue);//casewhenpublicstaticTResultIsNullTResult(TResultthisValue,TResultifNullValue);//sql里的IsNullpublicstaticboolIsNullOrEmpty(objectthisValue);//判断是否是Null或者空publicstaticintLength(objectvalue);//取长度publicstaticTResultMappingColumnTResult(TResultoldColumnName,stringnewColumnName);//列名映射publicstaticstringMergeString(stringvalue1,stringvalue2);publicstaticstringMergeString(stringvalue1,stringvalue2,stringvalue3,stringvalue4);publicstaticstringMergeString(stringvalue1,stringvalue2,stringvalue3,stringvalue4,stringvalue5);publicstaticstringMergeString(stringvalue1,stringvalue2,stringvalue3,stringvalue4,stringvalue5,stringvalue6);publicstaticstringMergeString(stringvalue1,stringvalue2,stringvalue3);publicstaticstringMergeString(stringvalue1,stringvalue2,stringvalue3,stringvalue4,stringvalue5,stringvalue6,stringvalue7);publicstaticstringReplace(objectvalue,stringoldChar,stringnewChar);//替换publicstaticboolStartsWith(stringthisValue,stringparameterValue);publicstaticSubqueryableTSubqueryableT()whereT:class,new();publicstaticstringSubstring(objectvalue,intindex,intlength);//获取子串publicstaticboolToBool(objectvalue);//类型转换publicstaticDateTimeToDate(objectvalue);//类型转换publicstaticdecimalToDecimal(objectvalue);//类型转换publicstaticdoubleToDouble(objectvalue);//类型转换publicstaticGuidToGuid(objectvalue);//类型转换publicstaticintToInt32(objectvalue);//类型转换publicstaticlongToInt64(objectvalue);//类型转换publicstaticstringToLower(objectthisValue);//类型转换publicstaticstringToString(objectvalue);//类型转换publicstaticTimeSpanToTime(objectvalue);//类型转换publicstaticstringToUpper(objectthisValue);//类型转换publicstaticstringTrim(objectthisValue);//去除首尾的空格}

这里的方法大多简单直接,我就不一一演示了。

1.3动态查询

之前我们写的查询条件都是固定好的,至少在编程的时候就知道最终查询条件是什么了。但是在开发过程中,有时候并不会那么早的知道最终查询条件或者说查询需要根据用户输入来调整查询条件,那么如何实现呢?

常见的解决方案有以下几种:

使用SQL语句,动态拼接SQL语句,然后根据SQL语句执行返回结果

在使用Lambda表达式时,进行动态拼接Lambda表达式

获取IQueryable接口,然后根据条件添加方法进行查询

这三种方法各有优略,使用查询接口会有一个明显的问题就是对应用层开放了更高的权限,使用SQL语句也是同样的道理。所以更符合逻辑的是使用动态拼接Lambda表达式。

当然,SqlSugar在这三种方案之上,提供了另外两种方案:

正是上一篇文中提到的IConditionalModel和WhereIF。我们先来看一下IConditionalModel如何使用:

varconditions=newListIConditionalModel();varquery=context.Client.QueryablePerson().Where(conditions);

可以在Where中传入IConditionModel类型。SqlSugar提供了两个受支持的实现类:

publicclassConditionalCollections:IConditionalModel{publicConditionalCollections();publicListKeyValuePairWhereType,ConditionalModelConditionalList{get;set;}}publicclassConditionalModel:IConditionalModel{publicConditionalModel();publicstringFieldName{get;set;}publicstringFieldValue{get;set;}publicConditionalTypeConditionalType{get;set;}publicFuncstring,objectFieldValueConvertFunc{get;set;}}

对于一个集合里的兄弟ConditionModel,表示查询条件都是and关系。而ConditionCollections则不同,其中ConditionList表示是一个键值对集合。键是WhereType类型,ConditionModel是值。我们先说说WhereType:

publicenumWhereType{And=0,Or=1}

分别表示And,Or。怎样理解呢?就是说,这一条键值对与前一个关系模型是And还是Or。

看一下示例:

//andid=and(id=1orid=2andid=1)conModels.Add(newConditionalModel(){FieldName="id",ConditionalType=ConditionalType.Equal,FieldValue=""});conModels.Add(newConditionalCollections(){ConditionalList=newListKeyValuePairWhereType,SqlSugar.ConditionalModel(){newKeyValuePairWhereType,ConditionalModel(WhereType.And,newConditionalModel(){FieldName="id",ConditionalType=ConditionalType.Equal,FieldValue="1"}),newKeyValuePairWhereType,ConditionalModel(WhereType.Or,newConditionalModel(){FieldName="id",ConditionalType=ConditionalType.Equal,FieldValue="2"}),newKeyValuePairWhereType,ConditionalModel(WhereType.And,newConditionalModel(){FieldName="id",ConditionalType=ConditionalType.Equal,FieldValue="2"})}});varstudent=db.QueryableStudent().Where(conModels).ToList();

继续看一下WhereIF,WhereIF的使用就相对简单一点:

ISugarQueryableTWhereIF(boolisWhere,ExpressionFuncT,boolexpression);

示例代码:

varquery=context.Client.QueryablePerson().WhereIF(string.IsNullOrEmpty(input),p=p.Age10);

理解起来也很容易,第一个参数如何结果为False,则不执行后续的查询,否则就执行。

2.一些高级玩法

除了增删改查,SqlSugar还提供了一些别的有意思的机制,继续我们的探索吧。

2.1批量操作

SqlSugar提供了一种一次性记录很多操作然后统一提交执行的模式,之前的操作都是仅支持批量插入、批量修改、批量删除。在这种模式下,SqlSugar还支持了批量(插入、修改、删除)。也就是说,在一个批处理中,即可以插入也可以修改还可以删除。

那么我们来看如何让这个功能为我们所用吧:

voidAddQueue();

在IDeleteable、IInsertable、IUpdateable、ISugarQueryable都有这个方法,一旦调用这个方法就表示该条指令进行缓存不立即执行,直到调用SqlSugarClient.SaveQueues()。通过调用SaveQueues()保存到数据库中。

值得注意的是:

SqlSugar虽然支持将查询也加入到批量操作的支持中,但是这部分在我看来更像是为了保证接口一致化而作的。个人并不推荐在批处理中加入查询,因为查询更多的需要及时准确快速,如果一旦陷入批处理中,查询就无法准确快速的返回数据了。

这样对于设定批处理的初衷,反而是违背的。当然最重要的一点,实际开发中这种情况很少遇到。

2.2事务

SQL本身支持事务,大多数ORM都支持事务,SqlSugar也不例外。SqlSugar通过哪些方法来自己实现一个事务呢?

在SqlSugarClient中执行:

publicvoidBeginTran();

会将SqlSugarClient做一个事务标记,表示之后的操作都是在事务中,直到事务提交或者回滚。

在SimpleClient中执行:

publicITenantAsTenant();

返回一个ITenant实例,然后通过这个实例提交事务或者回滚事务。

注意,SqlSugar所有的事务都是针对SqlSugarClient级别的,也就是说一个事务,一个SqlSugarClient。

2.3原生SQL执行

SqlSugar在很多地方都添加了原生Sql的支持。

比如说通过如下这种方式,可以使用Sql语句进行查询:

vart12=context.Client.SqlQueryableStudent("select*fromstudent").Where(it=it.id0).ToPageList(1,2);

通过以下这种方式,执行SQL:

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

然后,通过以下方式执行存储过程:

context.Client.Ado.UseStoredProcedure()3.总结

优秀的ORM总是有各种各样的方案,也有各种各样的优点。SqlSugar到目前为止,可以告一段落了。当然,我还是剩下了一部分,留给大伙自己去探索挖掘。接下来,我将以Dapper作为《C#数据操作系列》的最后内容。之后将会以项目的形式,带领大家去了解并学习asp.netcore。

高先生工作室

感谢(?′ω`?)您的每一份赞赏


转载请注明原文网址:http://www.helimiaopu.com/jsyy/7763.html

------分隔线----------------------------