我尝试从旧版本迁移到JPA2 Criteria API(Hibernate作为JPA提供程序)。我有PostgreSQL JSONB类型的自定义标准的问题。在之前的Criteria实现中,可以通过创建SQLCriterion来完成,我可以在本机SQL上直接操作。在JPA2实现中我找不到类似的解决方案,所以我决定扩展AbstractSimplePredicate。
这里简单的版本:
class JsonEqual<Y> extends AbstractSimplePredicate {
private static final String JSON_NESTED_FIELD_EXTRACTOR = "->>";
private static final String JSON_EQUAL_OPERATOR = "=";
private final Expression<?> field;
private final Expression<?> value;
private final Path<Y> path;
public JsonEqual(CriteriaBuilderImpl cb, Path<Y> path, Expression<?> field, Expression<?> value) {
super(cb);
this.path = path;
this.field = field;
this.value = value;
}
@Override
public void registerParameters(ParameterRegistry registry) {
Helper.possibleParameter(path, registry);
Helper.possibleParameter(field, registry);
Helper.possibleParameter(value, registry);
}
@Override
public String render(boolean isNegated, RenderingContext renderingContext) {
return ((Renderable) path).render(renderingContext)
+ JSON_NESTED_FIELD_EXTRACTOR
+ ((Renderable) field).render(renderingContext)
+ JSON_EQUAL_OPERATOR
+ ((Renderable) value).render(renderingContext);
}
}
将jpa2条件编译为HQL时出现问题。由谓词呈现的查询部分格式不正确(&#39; - &gt;&gt;&#39;运算符无法识别)。
org.hibernate.hql.internal.ast.QuerySyntaxException: unexpected token: > near line 1, column 515 [select new com.hibernate.VenueEntity(generatedAlias0.id) from com.hibernate.VenueEntity as generatedAlias0 where ( generatedAlias0.metadata->>:param3=:param4 ) order by generatedAlias0.created asc]
at org.hibernate.hql.internal.ast.QuerySyntaxException.convert(QuerySyntaxException.java:74) ~[hibernate-core-5.2.12.Final.jar:5.2.12.Final]
at org.hibernate.hql.internal.ast.ErrorCounter.throwQueryException(ErrorCounter.java:91) ~[hibernate-core-5.2.12.Final.jar:5.2.12.Final]
at org.hibernate.hql.internal.ast.QueryTranslatorImpl.parse(QueryTranslatorImpl.java:291) ~[hibernate-core-5.2.12.Final.jar:5.2.12.Final]
at org.hibernate.hql.internal.ast.QueryTranslatorImpl.doCompile(QueryTranslatorImpl.java:186) ~[hibernate-core-5.2.12.Final.jar:5.2.12.Final]
at org.hibernate.hql.internal.ast.QueryTranslatorImpl.compile(QueryTranslatorImpl.java:141) ~[hibernate-core-5.2.12.Final.jar:5.2.12.Final]
at org.hibernate.engine.query.spi.HQLQueryPlan.<init>(HQLQueryPlan.java:115) ~[hibernate-core-5.2.12.Final.jar:5.2.12.Final]
at org.hibernate.engine.query.spi.HQLQueryPlan.<init>(HQLQueryPlan.java:77) ~[hibernate-core-5.2.12.Final.jar:5.2.12.Final]
at org.hibernate.engine.query.spi.QueryPlanCache.getHQLQueryPlan(QueryPlanCache.java:153) ~[hibernate-core-5.2.12.Final.jar:5.2.12.Final]
at org.hibernate.internal.AbstractSharedSessionContract.getQueryPlan(AbstractSharedSessionContract.java:553) ~[hibernate-core-5.2.12.Final.jar:5.2.12.Final]
at org.hibernate.internal.AbstractSharedSessionContract.createQuery(AbstractSharedSessionContract.java:662) ~[hibernate-core-5.2.12.Final.jar:5.2.12.Final]
at org.hibernate.internal.SessionImpl.createQuery(SessionImpl.java:3324) ~[hibernate-core-5.2.12.Final.jar:5.2.12.Final]
at org.hibernate.query.criteria.internal.CriteriaQueryImpl$1.buildCompiledQuery(CriteriaQueryImpl.java:318) ~[hibernate-core-5.2.12.Final.jar:5.2.12.Final]
at org.hibernate.query.criteria.internal.compile.CriteriaCompiler.compile(CriteriaCompiler.java:149) ~[hibernate-core-5.2.12.Final.jar:5.2.12.Final]
at org.hibernate.internal.SessionImpl.createQuery(SessionImpl.java:3617) ~[hibernate-core-5.2.12.Final.jar:5.2.12.Final]
at org.hibernate.internal.SessionImpl.createQuery(SessionImpl.java:203) ~[hibernate-core-5.2.12.Final.jar:5.2.12.Final]
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method) ~[na:1.8.0_152]
at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62) ~[na:1.8.0_152]
at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43) ~[na:1.8.0_152]
at java.lang.reflect.Method.invoke(Method.java:498) ~[na:1.8.0_152]
在这种情况下,是否有可能为JPA2实现自定义谓词?
答案 0 :(得分:0)
我没有尝试用JSONB做这样的事情,但是我使用了数组和&&
运算符。
所以,我认为,以下解决方案将解决您的情况:
registerFunction("json_extract",
new SQLFunctionTemplate(HibernateTypeWhichYouNeed.INSTANCE, "(?1 ->> ?2)"));
cb.equal(
cb.function(json_extract, JavaClassWhatYouNeed.class, expr1, expr2),
expr3);