JPA:QueryCriteria WHERE子句中的谓词和表达式
我有一种情况,在我的WHERE子句中,我只有一个谓词和表达式。并且两者都需要在WHERE子句中进行AND运算:
Expression<String> col1 = tableEntity.get("col1");
Expression<String> regExpr = criteriaBuilder.literal("\.\d+$");
Expression<Boolean> regExprLike = criteriaBuilder.function("regexp_like", Boolean.class, col, regExpr);
Expression<TableEntity> col2= tableEntity.get("col2");
Predicate predicateNull = criteriaBuilder.isNull(col2);
createQuery.where(cb.and(predicateNull));
createQuery.where(regExprLike);
在这种情况下,我无法执行以下操作:
createQuery.where(dicateNull,regExprLike);
我尝试使用CriteriaBuilder的isTrue()方法:
Predicate predicateNull = criteriaBuilder.isNull(col2);
Predicate predicateTrue = criteriaBuilder.isTrue(regExprLike);
createQuery.where(predicateNull, predicateTrue);
但无济于事。
CriteriaQuery在WHERE子句中允许谓词或表达式,但不允许两者都允许。您知道如何在QueryCriteria的WHERE子句中同时使用、谓词和表达式吗?
更新2014年10月10日: 按照Chris的建议,我尝试使用:
createQuery.where(predicateNull, regExprLike);
但我的查询失败,出现异常:
Caused by: org.jboss.arquillian.test.spi.ArquillianProxyException: org.hibernate.hql.internal.ast.QuerySyntaxException : unexpected AST node: ( near line 1, column 311 [select coalesce(substring(generatedAlias0.col1,0,(locate(regexp_substr(generatedAlias0.col1, :param0),
generatedAlias0.col1)-1)), generatedAlias0.col1), generatedAlias0.col1
from com.temp.TableEntity as generatedAlias0
where (generatedAlias0.col2 is null ) and ( regexp_like(generatedAlias0.col1, :param1))] [Proxied because : Original exception not deserilizable, ClassNotFoundException]
我的代码如下:
CriteriaBuilder criteriaBuilder = entityManager.getCriteriaBuilder();
CriteriaQuery<Object[]> createQuery = criteriaBuilder.createQuery(Object[].class);
Root<TableEntity> tableEntity = createQuery.from(TableEntity.class);
Expression<String> path = tableEntity.get("col1");
Expression<String> regExpr = criteriaBuilder.literal("\.\d+$");
Expression<String> regExprSubStr = criteriaBuilder.function("regexp_substr", String.class, path, regExpr);
Expression<Boolean> regExprLike = criteriaBuilder.function("regexp_like", Boolean.class, path, regExpr);
Expression<Integer> l3 = criteriaBuilder.locate(path, regExprSubStr);
Expression<Integer> minusOne = criteriaBuilder.literal(1);
Expression<Integer> l3Sub1 = criteriaBuilder.diff(l3, minusOne);
Expression<Integer> zeroIndex = criteriaBuilder.literal(0);
Expression<String> s3 = criteriaBuilder.substring(path, zeroIndex, l3Sub1);
Expression<TableEntity> col1 = tableEntity.get("col1");
Expression<TableEntity> col2 = tableEntity.get("col2");
Expression<String> coalesceExpr = criteriaBuilder.coalesce(s3, path);
createQuery.multiselect(coalesceExpr, col1);
Predicate predicateNull = criteriaBuilder.isNull(col2);
createQuery.where(criteriaBuilder.and(predicateNull, regExprLike));
String query = entityManager.createQuery(createQuery).unwrap(org.hibernate.Query.class).getQueryString();
解决方案
我认为您的问题是Oracle没有将‘regexp_like’分类为函数。要使其正常工作,您必须使用新的注册函数扩展Oracle方言:
public class Oracle12cExtendedDialect extends Oracle12cDialect {
public Oracle12cExtendedDialect() {
super();
registerFunction(
"regexp_like", new SQLFunctionTemplate(StandardBasicTypes.BOOLEAN,
"(case when (regexp_like(?1, ?2)) then 1 else 0 end)")
);
}
}
然后您可以更改WHERE子句:
createQuery.where(criteriaBuilder.and(predicateNull, criteriaBuilder.equal(regExprLike, 1)));
当然,您必须在sistence.xml中注册您的新方言
<property name="hibernate.dialect" value="path.to.your.dialect.class.Oracle12cExtendedDialect" />
相关文章