QueryDSL 查询条件的序列化与反序列化

本方法仅适用于 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

原文 

https://segmentfault.com/a/1190000021606554

本站部分文章源于互联网,本着传播知识、有益学习和研究的目的进行的转载,为网友免费提供。如有著作权人或出版方提出异议,本站将立即删除。如果您对文章转载有任何疑问请告之我们,以便我们及时纠正。

PS:推荐一个微信公众号: askHarries 或者qq群:474807195,里面会分享一些资深架构师录制的视频录像:有Spring,MyBatis,Netty源码分析,高并发、高性能、分布式、微服务架构的原理,JVM性能优化这些成为架构师必备的知识体系。还能领取免费的学习资源,目前受益良多

转载请注明原文出处:Harries Blog™ » QueryDSL 查询条件的序列化与反序列化

赞 (0)
分享到:更多 ()

评论 0

  • 昵称 (必填)
  • 邮箱 (必填)
  • 网址