本方法仅适用于 JPQL
构造查询条件并序列化到文本字符串
QueryDSL 提供了 com.querydsl.core.types.Visitor
以访问 DSL 结点,在此基础上提供了 com.querydsl.core.support.SerializerBase
以序列化 DSL,该接口对应 JPQL 的实现为 com.querydsl.jpa.JPQLSerializer
.
主要用到的方法:
com.querydsl.core.support.SerializerBase#handle(com.querydsl.core.types.Expression<?>)
用以序列化条件 ( com.querydsl.core.types.Predicate
).
首先构造一个查询条件:
final Predicate predicate = QEduAction.eduAction.id.eq(2L)
.and(QEduAction.eduAction.name.like("%:GetCurrentTime"));
然后以 HQL 风格序列化到文本字符串:
JPQLSerializer jpqlSerializer = new JPQLSerializer(new HQLTemplates());
jpqlSerializer.handle(predicate);
String jpql = jpqlSerializer.toString();
// eduAction.id = ?1 and eduAction.name like ?2 escape '!'
com.querydsl.jpa.JPQLTemplates
的默认实现有很多个,针对项目选择,这里使用com.querydsl.jpa.HQLTemplates
.
关于查询条件序列化时丢失参数的问题
由于此法本质上是将查询条件序列化为模板,因此参数并不会跟着序列化.
如果需要解析出参数也不是不行,通过构造 com.querydsl.core.QueryMetadata
来获取 com.querydsl.core.types.PredicateOperation
并遍历其 args
节点,但是这里就需要分辨节点上是 Path
还是常量值,这部分涉及到的问题比较多,简单粗暴的办法则是直接提前构造参数列表.
List<Object> args = new ArrayList<>();
args.put(2L);
args.put("%s:GetCurrentTime");
final Predicate predicate = QEduAction.eduAction.id.eq((Long) args.get(0))
.and(QEduAction.eduAction.name.like((String) args.get(1));
然后将参数列表也序列化,这个就很容易了,直接转成 JSON 即可.
反序列化查询条件
核心点在于使用 com.querydsl.core.types.dsl.Expressions#booleanTemplate(java.lang.String, java.lang.Object...)
来通过字符串构造模板后生成查询条件.
int argIndex = 0;
StringBuilder stringBuilder = new StringBuilder();
// 由于模板使用的参数占位符是 {#index} 而不是 HQL 的 ?#index,因此这里需要转换一下.
final String[] split = jpql.split("\\?\\d+");
for (int i = 0; i < split.length; i++) {
if (i == split.length - 1) {
continue;
}
stringBuilder.append(String.format("%s{%s}", split[i], argIndex++));
}
jpql = stringBuilder.toString();
// eduAction.id = {0} and eduAction.name like {1}
其实这一步可以直接在序列化后顺便做了.
直接作为查询条件使用
new JPAQueryFactory(entityManager.getEntityManager())
.select(QEduAction.eduAction)
.from(QEduAction.eduAction)
.where(
Expressions.booleanTemplate(jpql, 2L, "%:GetCurrentTime")
);
参数列表从前面生成的 JSON 反序列化而来.
作为附加查询条件使用
final BooleanTemplate booleanTemplate = Expressions.booleanTemplate(jpql, 2L, "%:GetCurrentTime");
final JPAQuery<EduAction> query = new JPAQueryFactory(entityManager.getEntityManager())
.select(QEduAction.eduAction)
.from(QEduAction.eduAction)
.where(QEduAction.eduAction.policies.isEmpty());
query.getMetadata().addWhere(booleanTemplate);
生成的 HQL 为:
select eduAction
from EduAction eduAction
where eduAction.policies is empty and eduAction.id = ?1 and eduAction.name like ?2
**粗体** _斜体_ [链接](http://example.com) `代码` - 列表 > 引用
。你还可以使用@
来通知其他用户。