QueryDSL 查詢條件的序列化與反序列化

本方法僅適用於 JPQL

構造查詢條件並序列化到文本字符串

QueryDSL 提供了 com.querydsl.core.types.Visitor 以訪問 DSL 結點,在此基礎上提供了 com.querydsl.core.support.SerializerBase 以序列化 DSL,該接口對應 JPQL 的實現爲 com.querydsl.jpa.JPQLSerializer.java

主要用到的方法:sql

com.querydsl.core.support.SerializerBase#handle(com.querydsl.core.types.Expression<?>) 用以序列化條件 ( com.querydsl.core.types.Predicate ).app

首先構造一個查詢條件:ui

final Predicate predicate = QEduAction.eduAction.id.eq(2L)
    .and(QEduAction.eduAction.name.like("%:GetCurrentTime"));

而後以 HQL 風格序列化到文本字符串:code

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 .

關於查詢條件序列化時丟失參數的問題

因爲此法本質上是將查詢條件序列化爲模板,所以參數並不會跟着序列化.orm

若是須要解析出參數也不是不行,經過構造 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 便可.ci

反序列化查詢條件

核心點在於使用 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 爲:get

select eduAction
from EduAction eduAction
where eduAction.policies is empty and eduAction.id = ?1 and eduAction.name like ?2
相關文章
相關標籤/搜索