本方法僅適用於 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