基于Expression Lambda表达式树的通用复杂查询构建器——《摘要篇》
基于表达式树的通用查询构造器 常见的使用Linq Expression的做法这种代码众多,随便一搜就是, 但几乎都是单个条件的,单层级的,只能简单组装,组装成如:
Field_A =1 and Field_B =2 Or Field_C=3
--或者
Field_A =1 and (Field_B =2 Or Field_C=3)
是否可以灵活的查询条件组合 &独立的分离式的描述式条件,描述与执行分离的 &适应任何DTO的通用方案呢。
我们先来考查一个最简单的Sql where
子句: Id=1
当中有三种节点,分别为字段名:id,比较符:=,查询值:1 通过观察,我们用Name
来标识字段名,Op
来标识比较符,Value
来标识查询值,那么数据结构可以设计为 :
{ "Name" : "id", "Op" : "=", "Value" : 1 }
再来考查具有两个条件的子句:
Id=1 and name="MyName"
比上一条多了逻辑符:“and”,
那么我们添加两个节点,用Predicates
来描述查询条件,用Lg
来标识逻辑串接,数据结构可以设计为
[
{
"lg" : "",
"Predicates" : {"Name" : "id", "Op" : "=", "Value" : 1 }
},
{
"lg":"and",
"Predicates": { "Name" : "Name", "Op" : "=", "Value" : "MyName"}
}
]
以下两条子句都比较常用,也都属于简单的子句,再来看稍微复杂点儿的子句:
Id>1 and Id<10 and (Name="MyName" or Name="HisName")
比上一条多了一对分组括号: 添加节点filters
来容纳逻辑组合,数据结构可以设计为:
{
"lg": "",
"filters":
[
{
"lg": "",
"Predicates":[ { "lg": "", "Name": "id", "Op": ">", "Value": 1 } ]
},
{
"lg": "and",
"Predicates":[ { "lg": "", "Name": "id", "Op": "<", "Value": 10 } ]
},
{
"lg": "and",
"Predicates":
[
{"lg": "","Name": "name", "Op": "=", "Value": "MyName"},
{"lg": "or","Name": "name","Op": "=","Value": "HisName"}
]
}
]
}
--更复杂一点的等等:
Id=1
and (
(Name="MyName" or Name="HisName") or (Phone like"13899%" and Emil Like "%@xx.com")
)
基于此,期望能够以简洁的方式:
Query.Where(QueryFilterBuilder.CreateFilterExpression<Entity>(conditionBlock));
实现如下复杂的查询组合的复杂查询构建器:
where
(
(
(A.Field_A + A.Field_B) / A.Field_C=(2+3) % 2 or A.Field_A= A.Field_C
or (A.Field_C > 2 and Len(A.Field_D) < 2)
)
and (A.Field_E Like"%xxooxx" or A.Field_F in (1,2,3))
)
and A.Field_G in (select B.Field_N From B where cast(B.Fieild_DatetimeString as Datetime) = A.FieldDatetime)
)
如上所示,几乎可以实现任意条件,任意逻辑的组合查询。
理想这么美好,那么现实如何去实现,我们设计一个用来描述条件的对象:ConditionBlock用来承载上述查询条件的数据结构,再设计一个条件分析构造器:QueryFilterBuilder,使用它来创建Expression表达式树以构造Lambda查询表达式,由于条件描述与表达式构造分离,条件描述的工作可以放在任何地方,比如浏览器,它可以只需要提供符合数据结构的Json数据即可。
先看看总体代码:
https://github.com/ls0001/QueryFilter(别忘记随手点亮一颗小星星哦/^.^)
欲了解更多,挖掘更多,敬待下期分解。