动态表达式

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()//这个类需要自已定义下面有
            };
            
 
 //导航属性动态
 var list3 = db.Queryable<UnitPerson011>().Where("it", $"SqlFunc.Exists(it.Address.Id)").ToList();
 
 //普通条件动态
 var list4 = db.Queryable<UnitPerson011>().Where("it", $"it.Name={"a"}").ToList();
 
 //动态类+动态条件
 var list5=db.QueryableByObject(typeof(UnitPerson011)).Where("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;
            }
      }
        
/****参数说明****/
 
//硬编码  Id>1
FormattableString str = $"it.Id>1";
  
//固定字段+参数化变量 Id>@p=1
FormattableString str2 = FormattableStringFactory.Create("it.Id>{0}",1);
  
//动态字段+参数化变量 Id>@p=1
var p="it.Id";
FormattableString str2 = FormattableStringFactory.Create(p+">{0}",1);

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

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 更改列名

var data=new MappingColumn() 
                { DbColumnName = "OrderId", 
                 PropertyName = "Id", 
                 EntityName = "Order" };
expContext.MappingColumns.Add(data);
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报错

方案1:

 底层是用递归解析表达式,递归受到限制超过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);//设置等待时间保证这个 线程执行完

方案2:

高版本支持List.Any

.Where(it=>List.Any(s=>s.id==it.id&&s.name==it.id2))


关闭
果糖网