🎖️动态表达式的应用场景和优势 :
🔸动态查询:通过动态表达式,可以在运行时根据不同的条件构建查询语句,适用于 复杂 的查询逻辑和 灵活 的查询需求。
🔸减少硬编码:避免 了在代码中硬编码 SQL 语句,减少了维护成本和出错的可能性。
🔸提高开发效率:开发者可以专注于 业务逻辑 的实现,而不是低层次的数据库操作。
🔸增强安全性:动态表达式可以 减少SQL注入 等安全风险,因为 参数化查询 可以自动处理。
🎯**动态表达式 **可以方便动态表达式实现业务处理 ,当我们的业务场景需要N多聚合查询条件时,这个功能尤为重要。
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
1.4 去掉1==1 🔖
var ex=Expressionable.Create<Student03>()
.AndIf(id>0,it=>it.Id==id).ToExpression();
//如果一个条件没有有,你又不想生成1=1,可以结合whereif实现
var isEmpty = ((ex as LambdaExpression).Body as ConstantExpression)?.Value?.Equals(true)==true;
var students = db.Queryable<Student03>()
.WhereIF(!isEmpty, ex).ToList();
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:
较高版本支持 List.Any 和 List.All
.Where(it=>List.Any(s=>s.id==it.id&&s.name==it.id2))//高版本支持 OR
.Where(it=>List.All(s=>s.id==it.id&&s.name==it.id2))//高版本支持 AND
🧮方案2:
底层是用 递归解析 表达式,递归受到限制 超过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);//设置等待时间保证这个 线程执行完
** .NET开源 ORM 框架 SqlSugar 系列**
- 【开篇】.NET开源 ORM 框架 SqlSugar 系列
- 【入门必看】.NET开源 ORM 框架 SqlSugar 系列
- 【实体配置】.NET开源 ORM 框架 SqlSugar 系列
- 【Db First】.NET开源 ORM 框架 SqlSugar 系列
- 【Code First】.NET开源 ORM 框架 SqlSugar 系列
- 【数据事务】.NET开源 ORM 框架 SqlSugar 系列
- 【连接池】.NET开源 ORM 框架 SqlSugar 系列
- 【查询目录】.NET开源 ORM 框架 SqlSugar 系列
- 【查询基础】.NET开源 ORM 框架 SqlSugar 系列
- 【排序用法】.NET开源 ORM 框架 SqlSugar 系列
- 【分组去重】.NET开源 ORM 框架 SqlSugar 系列
- 【联表查询】.NET开源 ORM 框架 SqlSugar 系列
- 【导航查询】.NET开源 ORM 框架 SqlSugar 系列
- 【子查询】.NET开源 ORM 框架 SqlSugar 系列
- 【嵌套查询】.NET开源 ORM 框架 SqlSugar 系列
- 【配置查询】.NET开源 ORM 框架 SqlSugar 系列
- 【并集查询】.NET开源 ORM 框架 SqlSugar 系列
- 【树型查询】.NET开源 ORM 框架 SqlSugar 系列
- 【表格查询】.NET开源 ORM 框架 SqlSugar 系列
❤️关注、👍点赞、🔶收藏 💞
版权归原作者 Microi风闲 所有, 如有侵权,请联系我们删除。