自动模型AutoModel
目标
- 面向接口,支持依赖注入
- 开箱即用
- 无需耦合实体代码
用法
目前MoCrudAppService
中有使用到该技术,对于查询请求提供Filter
,Select
,Fuzzy
等字段。
提供
语法
<FieldName1> <Condition1> "<Value1>" [or|and|&&|||] <FieldName2> <Condition2> "<Value2>"
- FieldName: 字段名(默认是实体属性名)
- Condition:条件关键字,目前包含
in
,like
,=
,>
,<
,>=
,<=
,!=
,explike
- Value: 字段比较值。以
"
双引号包裹。内部语法根据条件关键字、字段类型变化而变化。
字段名
目前可用字段名即实体属性名
条件关键字
以下是有特殊功能的条件关键字
like
- 字段类型为字符串时
test
代表%test%
,查询包含test
的test%
代表以test
开头的,即与数据库模糊相同(当含有%
原样输出)
explike
与:&
或:|
非:!
, !
模糊:%
括号:(
,)
,(
, )
- 字段类型为字符串时
ABC
字符串包含ABC
!ABC
字符串不包含ABC
ABC & CD
字符串包含ABC
且包含CD
ABC | CD
字符串包含ABC
或包含CD
ABC%
字符串以ABC
开头A%BC
字符串以A
开头BC
结尾- 高阶:
(AB%C | B C) & (!CE% & !CD)
字符串相似AB%C
或包含B C
,而且字符串不以CE
开头且不包含CD
in
- 字段类型为字符串时
佛山,深圳
字符串等于佛山或等于深圳
- 字段类型为时间时(暂未实现)
EOBT in "[now, now+30min]"
字段比较值
内部会将传入的字符串比较值转为实体字段相关类型进行比较。
目前支持的类型:double
,int
,long
,Enum
,string
,boolean
,DateTime
,DateOnly
,TimeOnly
,Guid
,TimeSpan
DateTime,DateOnly类型
支持格式为yyyy-MM-dd
, yyyyMMdd
, MMdd
, yyyy-MM-dd HHmmss
, yyMMdd
以及时间表达式:Now
, Now+30min
时间表达式
当前时间:now
增加某时间长度后的时间:now + 60min
减去某时间长度后的时间:now - 3.6h
, yyyy-MM-dd + 60min
支持连续加减
- 仅支持
+
或-
TimeSpan类型
支持格式为HH:mm:ss
, HHmm
以及特殊时间长度:
- 分钟(minutes):
1min
- 小时(hour):
3.6h
- 秒(second):
114s
- 天数(day):
1d
开发使用
结合仓储层
protected IAutoModelDbOperator<PlanNoticeMsg> _autoDb =>
LazyServiceProvider.LazyGetService<IAutoModelDbOperator<PlanNoticeMsg>>()!;
protected IRepositoryPlanNoticeMsg _msg;
var query = await _msg.GetQueryableAsync(true);
_autoDb.ApplyFilter(query, $"""
{nameof(PlanNoticeMsg.MsgContent)} like "CBD"
""");
query.ToListAsync();
自定义字段Query组装器(暂未实现)
CustomFor(nameof(Entity.FieldName), (input, querable))
前端请求类(暂未实现)
可以以传统方式编写请求类,前端不必拼接语句
引擎核心设计
引擎语法设计
本引擎本着简单易用的目的,设计了一个简明扼要的Query DSL
语法。因该DSL
面向实体,实体中有相关的属性数据,面向实体属性的筛选,表达式语法规则即:
<实体属性名> <条件关键字> "<属性比较值>"
例如航班计划实体FlightPlan
,其中含有Callsign
的实体属性,那么如果筛选航班计划中Callsign
包含3001
字符串的实体,表达式为:
Callsign like "3001"
本引擎把以上一个表达式称为一个Token
。另外,也支持括号及且(&&
)、或(||
)的关系表达式,如:
Token1 && (Token2 || Token3)
对于条件关键字,目前支持in
, like
, explike
, >
, <
, >=
, <=
, =
, !=
等条件,可由开发者自行扩展。对于属性比较值,语法及效果根据的条件关键字、实体属性的类型变化而变化。
引擎的模块划分及逻辑关系
引擎使用面向接口、依赖注入的方式实现,具体实现可供开发者进行替换或改造,主要分为应用接口与内部实现接口。应用接口面向开发者,即提供开箱即用的接口。内部实现主要代表引擎内部所有构建块,面向需求更复杂的开发者,可供灵活扩展引擎,实现不同的需求。引擎命名为AutoModel
,模块整体架构如图所示:
应用接口上,主要提供两种应用接口。一是适用于数据库的引擎功能接口,可以适用于LINQ to SQL
的表达式生成,将生成的过滤表达式运用于ORM
框架,实现针对数据库的动态过滤。二是适用于内存的引擎功能接口,可以适用于实体Lambda
表达式生成,生成Predicate<TEntity>
的方法委托,即传入为实体类型,返回值为布尔类型的函数指针。该方法委托可用于内存中IEnumerable<TEntity>
的类型筛选,即任何实体支持迭代的类型的筛选。
内部实现上,其中三种蓝色部分的接口用于Query DSL
字符串表达式的解析。剩余两种紫色部分的接口,快照用于缓存实体配 置及相关信息构建,类型转换器用于字符串过滤值至代码托管类型转换。
引擎交互流程
引擎交互流程通过一个例子进行解释:
其中表达式:
Callsign like "CCA%" && CreateTime >= "2024-12-25" && (EOBT > "now – 60min") || ATOT < "now + 3d")
表达式标准化器用于将表达式标准化为调用核心引擎的语法,当前实现的引擎为Dynamic LINQ
引擎。表达式实体字段Token
解析器用于对整个表达式进行Token
化分析。示例表达式可以被拆分为四个Token
,对于每个Token
进行进一步的信息填充。
以Callsign like"CCA%"
为例,识别实体属性名为Callsign
,条件关键字为like
,属性比较值为CCA%
。根据实体快照,对Token
的三个部分进行检查验证,明确是否为有效的Token
。最终会生成四个经过验证的Token
,通过Token
生成器生成适用于调用核心引擎的调用方式,进而作用于数据库或内存实体表中进行筛选。