动态表达式

1、动态表达式

 1.1 用例

可以方便动态表达式实现业务处理

//用例1:连写
Expression<Func<Order, bool>> exp = Expressionable.Create<Order>() //创建表达式
              .AndIF(p > 0, it => it.Id == p)
              .AndIF(name != null, it => it.Name == name && it.Sex==1)
              .ToExpression();//注意 这一句 不能少
              
var list = db.Queryable<Order>().Where(exp).ToList();//直接用就行了不需要判段 null和加true
  

//用例2:分开写法
var expable= Expressionable.Create<Order>();
...逻辑
expable.And(it.xx==x);
...逻辑
expable.And(it.yy==y);
...逻辑
var exp=expable.ToExpression();//要用变量 var exp=
db.Queryable<Order>().Where(exp).ToList()//直接用就行了不需要判段 null和加true

//用例3:多表查询
var exp=Expressionable.Create<Order,T2,T3>()
         .And((x,y,z)=>z.id==1).ToExpression();//注意 这一句 不能少
         
         
//技巧 WhereIF 有时候更方便
var list=db.Queryable<T>()
.WhereIF(p>0,it=>it.p==p)
.WhereIF(y>0,it=>it.y==y)
.ToList()

 1.2 拓展用例

我们可以用动态表达式实现 In ( name like 1, name  like2 , name  like3 ...)  in 的模糊查询

var names= new string [] { "a","b"};
Expressionable<Order> exp = Expressionable.Create<Order>();
foreach (var item in names)
{
    exp.Or(it => it.Name.Contains(item.ToString()));
}
var list= db.Queryable<Order>().Where(exp.ToExpression()).ToList();

生成的Sql

SELECT [Id],[Name],[Price],[CreateTime],[CustomId]
        FROM [Order]  WHERE (
                      ([Name] like '%'+ CAST(@MethodConst0 AS NVARCHAR(MAX))+'%') OR 
                      ([Name] like '%'+ CAST(@MethodConst1 AS NVARCHAR(MAX))+'%')
                     )

 1.3 Queyable.Or

我们可以通过.Where().Where实现多个AND如果想实现 OR就只能借助动态表达式实现,query.or 让表达式中可以用OR

 var exp = Expressionable.Create<Order>()
              .And(it => it.Id == 1)
              .Or(it=>it.Id==100 )
              .ToExpression();//注意 这一句 不能少
              
var list= db.Queryable<Order>().Where(exp).ToList();
//Sql
//   where id=1 or id=100


2、字符串 To 表达式

5.1.4.107-preview14+

 //程序启动时配置
  StaticConfig.DynamicExpressionParserType = typeof(DynamicExpressionParser);
  StaticConfig.DynamicExpressionParsingConfig = new ParsingConfig()//用到SqlFunc需要配置这个属性
            {
                CustomTypeProvider = new SqlSugarTypeProvider()//下面有
            };
            
 //注意:第二个参数必须要有$
 //参数化:可以缓存创建性能好
 //如果没有$ 需要用 FormattableStringFactory.Create("it.Id=={0}", 1)            
            
 //导航属性动态
 var list3 = db.Queryable<UnitPerson011>().Where("it", $"it=>SqlFunc.Exists(it.Address.Id)").ToList();
 
 //普通条件动态
 var list4 = db.Queryable<UnitPerson011>().Where("it", $"it=>it.Name={"a"}").ToList();
 
 //动态类+动态条件
 var list5=db.QueryableByObject(typeof(UnitPerson011)).Where("it", $"it=>it.Address.Id=={1}").ToList();
 
 
   //扩展类型          
   public class SqlSugarTypeProvider : DefaultDynamicLinqCustomTypeProvider
        {
            public override HashSet<Type> GetCustomTypes()
            {
                var customTypes = base.GetCustomTypes();
                customTypes.Add(typeof(SqlFunc));//识别SqlFunc
                return customTypes;
            }
        }

 该功能和表格查询可以互补


3、表达式 To Sql

如果你们老大只让你用Ado,你们也可以把SqlSugar当成表达式解析器

    var expContext = new SqlServerExpressionContext();
    Expression<Func<IOrder, bool>> exp = it => it.id==1;
    expContext.Resolve(exp, ResolveExpressType.WhereSingle);
    var wheresql = expContext.Result.GetString();
    
    var pars = expContext.Parameters;
    db.Queryable<Order>().Where(wheresql).AddParameters(pars).ToList();

 3.1 声名表达式解析器

ExpressionContext expContext=null;
switch (dbtype)
{
case DbType.MySql:
expContext = new MySqlExpressionContext();
break;
case DbType.SqlServer:
expContext = new SqlServerExpressionContext();
break;
case DbType.Sqlite:
expContext = new SqliteExpressionContext();
break;
case DbType.Oracle:
expContext = new OracleExpressionContext();
break;
case DbType.PostgreSQL:
expContext = new PostgreSQLExpressionContext();
break;
case DbType.Dm:
expContext = new DmExpressionContext();
break;
case DbType.Kdbndp:
expContext = new KdbndpExpressionContext();
break;
default:
throw new Exception("不支持");

 3.2 Where条件的解析

基本和写EF一样常用的都会支持

Expression<Func<DataTestInfo2, bool>> exp = it => it.Bool2== b.Value;
expContext.Resolve(exp, ResolveExpressType.WhereSingle);
var value = expContext.Result.GetString();
var pars = expContext.Parameters;
//( [Bool2] = @Bool20 ) //WhereSingle 没有别名 it

我们在写一个Like的例子

Expression<Func<Student, bool>> exp = it => it.Name.Contains(schoolData.Name);
ExpressionContext expContext = new ExpressionContext();
expContext.Resolve(exp, ResolveExpressType.WhereMultiple);
var value = expContext.Result.GetString();
var pars = expContext.Parameters;
//([it].[Name] like '%'+@MethodConst0+'%') //WhereMultiple解析后会有别我 [it].

 3.3 Select的解析

支持实体类解析、查询单个字段解析、匿名对象解析

Expression<Func<DataTestInfo2, DataTestInfo2>> exp =it => new DataTestInfo2() {  Bool1=it.Bool1 , Bool2=it.Bool2 };
ExpressionContext expContext = new ExpressionContext();
expContext.IsSingle = false;
expContext.Resolve(exp, ResolveExpressType.SelectSingle);
var selectorValue = expContext.Result.GetString();
var pars = expContext.Parameters;
//[Bool1] AS [Bool1] , [Bool2] AS [Bool2]

 3.4 字段名称的解析

例如orderby(it=>it.Name) 像这种我们就需要拿到Name

Expression<Func<Student, object>> exp = it => it.Name;
ExpressionContext expContext = GetContext();
expContext.Resolve(exp, ResolveExpressType.FieldSingle);
var selectorValue = expContext.Result.GetString();
//Name

 统计单 个字段

Expression<Func<Student, object>> exp = it =>SqlFunc.AggregateAvg(it.Id);
ExpressionContext expContext = GetContext();
expContext.Resolve(exp, ResolveExpressType.FieldMultiple);
var selectorValue = expContext.Result.GetString();
//AVG([it].[Id])

 3.5 更改列名

expContext.MappingColumns.Add(new MappingColumn() { DbColumnName = "OrderId", PropertyName = "Id", EntityName = "Order" });
Expression<Func<Order, bool>> exp = it => it.Id== 1;
expContext.Resolve(exp, ResolveExpressType.WhereSingle);
var value = expContext.Result.GetString();
var pars = expContext.Parameters;
//( [OrderId] = 1)


4、常见错误

 4.1 拼接超出1000报错

 底层是用递归解析表达式,递归受到限制超过1000就会报错 ,我们可以通过设置线程最大堆栈解决

 List<Order> list = null;
    var t=new System.Threading.Thread(async () =>
    {
        var expable = SqlSugar.Expressionable.Create<Order>();
        for (int i = 0; i < 1000; i++)
        {
            expable.Or(it => it.Id == i && it.Id == i);
        }
        var getOrderBy = db.Queryable<Order>().Where(expable.ToExpression()).ToListAsync();
        var x = 0;

    },int.MaxValue);//设置线程栈
    t.Start();
    Thread.Sleep(1000);//设置等待时间保证这个 线程执行完


关闭
文档:SqlSugar5.0