首先,对于长篇文章提前抱歉,但这是一个复杂的问题。
我们的产品目前使用标准api进行以下工作查询:
SELECT
pedido0_.rap_num_doc as col_0_0_,
pedido0_.rap_cod_tip_doc as col_0_1_,
pedido0_.rap_ver_doc as col_0_2_,
pedido0_.edo_cod_est_doc as col_1_0_,
pedido0_.tip_can as col_2_0_,
pedido0_.num_pro_rea as col_3_0_,
pedido0_.cod_uti_ges_ped as col_4_0_,
pedido0_.nom_ges_ped as col_5_0_,
pedido0_.dte_nifap as col_6_0_,
pedido0_.nom_tit as col_7_0_,
pedido0_.cod_uti_cri as col_8_0_,
pedido0_.uor_cod_uni_org as col_9_0_,
pedido0_.chv_cod_tip_ped as col_10_0_,
estadopedi3_.cod_est_ped as col_11_0_,
procedimen1_.cod_pro_ped as col_12_0_,
tipodecisa2_.cod_tip_dec_ped as col_13_0_,
pedido0_.uti_codigo as col_14_0_
FROM
rap_pedido pedido0_
LEFT OUTER JOIN
rap_pro_ped procedimen1_
on pedido0_.chv_cod_pro_ped=procedimen1_.cod_pro_ped
LEFT OUTER JOIN
rap_tip_dec_ped tipodecisa2_
on pedido0_.chv_cod_tip_dec_ped=tipodecisa2_.cod_tip_dec_ped
LEFT OUTER JOIN
rap_est_ped estadopedi3_
on pedido0_.chv_cod_est_ped=estadopedi3_.cod_est_ped
INNER JOIN
rap_tip_ped tipopedido4_
on pedido0_.chv_cod_tip_ped=tipopedido4_.cod_tip_ped
WHERE
pedido0_.dte_nif=?
我的目标是在select子句中对查询进行以下更改(添加了CASE语句):
SELECT
pedido0_.rap_num_doc as col_0_0_,
pedido0_.rap_cod_tip_doc as col_0_1_,
pedido0_.rap_ver_doc as col_0_2_,
pedido0_.edo_cod_est_doc as col_1_0_,
pedido0_.tip_can as col_2_0_,
pedido0_.num_pro_rea as col_3_0_,
pedido0_.cod_uti_ges_ped as col_4_0_,
pedido0_.nom_ges_ped as col_5_0_,
pedido0_.dte_nifap as col_6_0_,
pedido0_.nom_tit as col_7_0_,
pedido0_.cod_uti_cri as col_8_0_,
pedido0_.uor_cod_uni_org as col_9_0_,
pedido0_.chv_cod_tip_ped as col_10_0_,
estadopedi3_.cod_est_ped as col_11_0_,
procedimen1_.cod_pro_ped as col_12_0_,
tipodecisa2_.cod_tip_dec_ped as col_13_0_,
pedido0_.uti_codigo as col_14_0_ ,
CASE WHEN (pedido0_.rap_ver_doc = (
SELECT MAX(a.rap_ver_doc)
FROM rap_pedido a
WHERE a.rap_num_doc = pedido0_.rap_num_doc AND a.rap_cod_tip_doc = pedido0_.rap_cod_tip_doc AND a.edo_cod_est_doc > 3 AND NOT EXISTS (
SELECT 1
FROM rap_pedido b
WHERE b.rap_cod_tip_doc = a.rap_cod_tip_doc AND b.rap_num_doc = a.rap_num_doc AND b.rap_ver_doc > a.rap_ver_doc AND b.edo_cod_est_doc > 0
)
)
) THEN true ELSE false END
FROM
rap_pedido pedido0_
LEFT OUTER JOIN
rap_pro_ped procedimen1_
on pedido0_.chv_cod_pro_ped=procedimen1_.cod_pro_ped
LEFT OUTER JOIN
rap_tip_dec_ped tipodecisa2_
on pedido0_.chv_cod_tip_dec_ped=tipodecisa2_.cod_tip_dec_ped
LEFT OUTER JOIN
rap_est_ped estadopedi3_
on pedido0_.chv_cod_est_ped=estadopedi3_.cod_est_ped
INNER JOIN
rap_tip_ped tipopedido4_
on pedido0_.chv_cod_tip_ped=tipopedido4_.cod_tip_ped
WHERE
pedido0_.dte_nif=?
为了达到这个目的,我使用以下代码调整了当前的select子句:
// Begin new code
Subquery<Integer> subqueryUltimaVersaoDocumentoSubmetidoSemOutroCriado = criarSubqueryUltimaVersaoDocumentoSubmetidoSemOutroCriado(builder,
query, fromPedido);
Case<Boolean> booleanCase = builder.<Boolean> selectCase();
Predicate versaoIgual = builder.equal(fromPedido.get(Pedido_.id).get(PedidoPK_.versaoDocumento),
subqueryUltimaVersaoDocumentoSubmetidoSemOutroCriado);
Expression<Boolean> isSubstituicaoPermitida = booleanCase.when(versaoIgual, true).otherwise(false);
// End new code
query.select(builder.construct(Pedido.class, fromPedido.get(Pedido_.id), fromPedido.get(Pedido_.estadoDocumento),
fromPedido.get(Pedido_.tipoCandidatura), fromPedido.get(Pedido_.numeroProcesso), fromPedido.get(Pedido_.utilizadorGestor),
fromPedido.get(Pedido_.nomeGestor), fromPedido.get(Pedido_.nifapBeneficiario), fromPedido.get(Pedido_.nomeTitular),
fromPedido.get(Pedido_.utilizadorCriacao), fromPedido.get(Pedido_.unidadeOrganicaBeneficiario), fromPedido.get(Pedido_.tipoPedido),
joinEstadoPedido, joinProcedimento, joinTipoDecisao, fromPedido.get(Pedido_.utilizadorProprietario), isSubstituicaoPermitida));
调用子查询方法如下:
private Subquery<Integer> criarSubqueryUltimaVersaoDocumentoSubmetidoSemOutroCriado(final CriteriaBuilder builder,
final CriteriaQuery<Pedido> query, final Root<Pedido> fromPedido) {
// Select max(a.rap_ver_doc) From rap_pedido a Where a.rap_num_doc = pedido0_.rap_num_doc and a.rap_cod_tip_doc = pedido0_.rap_cod_tip_doc and
// a.edo_cod_est_doc > 3 and not exists ...
final Subquery<Integer> subqueryUltimaVersaoSubmetida = query.subquery(Integer.class);
final Root<Pedido> fromUltimaVersaoPedido = subqueryUltimaVersaoSubmetida.from(Pedido.class);
subqueryUltimaVersaoSubmetida.select(builder.max(fromUltimaVersaoPedido.get(Pedido_.id).get(PedidoPK_.versaoDocumento)));
final List<Predicate> where = new ArrayList<>();
adicionarWhereEquals(builder, where, fromUltimaVersaoPedido.get(Pedido_.id).get(PedidoPK_.tipoDocumento),
fromPedido.get(Pedido_.id).get(PedidoPK_.tipoDocumento));
adicionarWhereEquals(builder, where, fromUltimaVersaoPedido.get(Pedido_.id).get(PedidoPK_.numeroDocumento),
fromPedido.get(Pedido_.id).get(PedidoPK_.numeroDocumento));
// Considera todos os pedidos cujo estado seja igual ou maior ao estado passado como argumento
adicionarWhereGreaterThanOrEqualTo(builder, where, fromUltimaVersaoPedido.get(Pedido_.estadoDocumento),
EstadoDocumentoPedido.SUBMETIDO.getId());
builder.not(builder.exists(criarSubqueryExisteDocumentoCriado(builder, query, fromUltimaVersaoPedido)));
subqueryUltimaVersaoSubmetida.where(where.toArray(new Predicate[0]));
return subqueryUltimaVersaoSubmetida;
}
private Subquery<Integer> criarSubqueryExisteDocumentoCriado(CriteriaBuilder builder, CriteriaQuery<Pedido> query, Root<Pedido> fromPedido) {
// select 1 from rap_pedido b where b.rap_cod_tip_doc = a.rap_cod_tip_doc and b.rap_num_doc = a.rap_num_doc and b.rap_ver_doc > a.rap_ver_doc
// and b.edo_cod_est_doc > 0
final Subquery<Integer> subqueryUltimaVersao = query.subquery(Integer.class);
final Root<Pedido> fromUltimaVersaoPedido = subqueryUltimaVersao.from(Pedido.class);
subqueryUltimaVersao.select(builder.literal(1));
final List<Predicate> where = new ArrayList<>();
adicionarWhereEquals(builder, where, fromUltimaVersaoPedido.get(Pedido_.id).get(PedidoPK_.tipoDocumento),
fromPedido.get(Pedido_.id).get(PedidoPK_.tipoDocumento));
adicionarWhereEquals(builder, where, fromUltimaVersaoPedido.get(Pedido_.id).get(PedidoPK_.numeroDocumento),
fromPedido.get(Pedido_.id).get(PedidoPK_.numeroDocumento));
adicionarWhereGreaterThan(builder, where, fromUltimaVersaoPedido.get(Pedido_.id).get(PedidoPK_.versaoDocumento),
fromPedido.get(Pedido_.id).get(PedidoPK_.versaoDocumento));
adicionarWhereGreaterThan(builder, where, fromUltimaVersaoPedido.get(Pedido_.estadoDocumento), 0);
subqueryUltimaVersao.where(where.toArray(new Predicate[0]));
return subqueryUltimaVersao;
}
protected void adicionarWhereEquals(CriteriaBuilder builder, List<Predicate> where, Expression<?> coluna1, Expression<?> coluna2) {
where.add(builder.equal(coluna1, coluna2));
}
protected void adicionarWhereEquals(CriteriaBuilder builder, List<Predicate> where, Expression<?> coluna, Object parametro) {
where.add(builder.equal(coluna, parametro));
}
@SuppressWarnings({ "rawtypes", "unchecked" })
protected void adicionarWhereGreaterThanOrEqualTo(CriteriaBuilder builder, List<Predicate> where, Expression coluna, Comparable parametro) {
where.add(builder.greaterThanOrEqualTo(coluna, parametro));
}
@SuppressWarnings({ "rawtypes", "unchecked" })
protected void adicionarWhereGreaterThanOrEqualTo(CriteriaBuilder builder, List<Predicate> where, Expression coluna1, Expression coluna2) {
where.add(builder.greaterThanOrEqualTo(coluna1, coluna2));
}
@SuppressWarnings("unchecked")
protected void adicionarWhereGreaterThan(CriteriaBuilder builder, List<Predicate> where, Expression coluna1, Expression coluna2) {
where.add(builder.greaterThan(coluna1, coluna2));
}
@SuppressWarnings("unchecked")
protected void adicionarWhereGreaterThan(CriteriaBuilder builder, List<Predicate> where, Expression coluna, Comparable parametro) {
where.add(builder.greaterThanOrEqualTo(coluna, parametro));
}
但是,调用查询时出现以下异常。 select子句中添加的任何类型的子查询都给出了相同的结果。有解决方法吗?
Caused by: java.lang.ClassCastException: org.hibernate.hql.internal.ast.tree.ParameterNode cannot be cast to org.hibernate.hql.internal.ast.tree.SelectExpression
at org.hibernate.hql.internal.ast.tree.CaseNode.getFirstThenNode(CaseNode.java:43) [hibernate-core-4.2.0.Final-redhat-1.jar:4.2.0.Final-redhat-1]
at org.hibernate.hql.internal.ast.tree.CaseNode.getDataType(CaseNode.java:39) [hibernate-core-4.2.0.Final-redhat-1.jar:4.2.0.Final-redhat-1]
at org.hibernate.hql.internal.ast.tree.ConstructorNode.resolveConstructorArgumentTypes(ConstructorNode.java:166) [hibernate-core-4.2.0.Final-redhat-1.jar:4.2.0.Final-redhat-1]
at org.hibernate.hql.internal.ast.tree.ConstructorNode.prepare(ConstructorNode.java:141) [hibernate-core-4.2.0.Final-redhat-1.jar:4.2.0.Final-redhat-1]
at org.hibernate.hql.internal.ast.HqlSqlWalker.processConstructor(HqlSqlWalker.java:1019) [hibernate-core-4.2.0.Final-redhat-1.jar:4.2.0.Final-redhat-1]
at org.hibernate.hql.internal.antlr.HqlSqlBaseWalker.selectExpr(HqlSqlBaseWalker.java:2279) [hibernate-core-4.2.0.Final-redhat-1.jar:4.2.0.Final-redhat-1]
at org.hibernate.hql.internal.antlr.HqlSqlBaseWalker.selectExprList(HqlSqlBaseWalker.java:2145) [hibernate-core-4.2.0.Final-redhat-1.jar:4.2.0.Final-redhat-1]
at org.hibernate.hql.internal.antlr.HqlSqlBaseWalker.selectClause(HqlSqlBaseWalker.java:1451) [hibernate-core-4.2.0.Final-redhat-1.jar:4.2.0.Final-redhat-1]
at org.hibernate.hql.internal.antlr.HqlSqlBaseWalker.query(HqlSqlBaseWalker.java:571) [hibernate-core-4.2.0.Final-redhat-1.jar:4.2.0.Final-redhat-1]
at org.hibernate.hql.internal.antlr.HqlSqlBaseWalker.selectStatement(HqlSqlBaseWalker.java:299) [hibernate-core-4.2.0.Final-redhat-1.jar:4.2.0.Final-redhat-1]
at org.hibernate.hql.internal.antlr.HqlSqlBaseWalker.statement(HqlSqlBaseWalker.java:247) [hibernate-core-4.2.0.Final-redhat-1.jar:4.2.0.Final-redhat-1]
at org.hibernate.hql.internal.ast.QueryTranslatorImpl.analyze(QueryTranslatorImpl.java:248) [hibernate-core-4.2.0.Final-redhat-1.jar:4.2.0.Final-redhat-1]
at org.hibernate.hql.internal.ast.QueryTranslatorImpl.doCompile(QueryTranslatorImpl.java:183) [hibernate-core-4.2.0.Final-redhat-1.jar:4.2.0.Final-redhat-1]
at org.hibernate.hql.internal.ast.QueryTranslatorImpl.compile(QueryTranslatorImpl.java:136) [hibernate-core-4.2.0.Final-redhat-1.jar:4.2.0.Final-redhat-1]
at org.hibernate.engine.query.spi.HQLQueryPlan.<init>(HQLQueryPlan.java:105) [hibernate-core-4.2.0.Final-redhat-1.jar:4.2.0.Final-redhat-1]
at org.hibernate.engine.query.spi.HQLQueryPlan.<init>(HQLQueryPlan.java:80) [hibernate-core-4.2.0.Final-redhat-1.jar:4.2.0.Final-redhat-1]
at org.hibernate.engine.query.spi.QueryPlanCache.getHQLQueryPlan(QueryPlanCache.java:168) [hibernate-core-4.2.0.Final-redhat-1.jar:4.2.0.Final-redhat-1]
at org.hibernate.internal.AbstractSessionImpl.getHQLQueryPlan(AbstractSessionImpl.java:221) [hibernate-core-4.2.0.Final-redhat-1.jar:4.2.0.Final-redhat-1]
at org.hibernate.internal.AbstractSessionImpl.createQuery(AbstractSessionImpl.java:199) [hibernate-core-4.2.0.Final-redhat-1.jar:4.2.0.Final-redhat-1]
at org.hibernate.internal.SessionImpl.createQuery(SessionImpl.java:1777) [hibernate-core-4.2.0.Final-redhat-1.jar:4.2.0.Final-redhat-1]
at org.hibernate.ejb.AbstractEntityManagerImpl.createQuery(AbstractEntityManagerImpl.java:452) [hibernate-entitymanager-4.2.0.Final-redhat-1.jar:4.2.0.Final-redhat-1]
at org.hibernate.ejb.criteria.CriteriaQueryCompiler.compile(CriteriaQueryCompiler.java:221) [hibernate-entitymanager-4.2.0.Final-redhat-1.jar:4.2.0.Final-redhat-1]
at org.hibernate.ejb.AbstractEntityManagerImpl.createQuery(AbstractEntityManagerImpl.java:587) [hibernate-entitymanager-4.2.0.Final-redhat-1.jar:4.2.0.Final-redhat-1]
at org.jboss.as.jpa.container.AbstractEntityManager.createQuery(AbstractEntityManager.java:96) [jboss-as-jpa-7.1.1.Final.jar:7.1.1.Final]
....
谢谢!
答案 0 :(得分:1)
经过深入挖掘后,我想我找到了答案。
显然,由于我使用JPA 2.0和Hibernate 4.2.0作为提供程序,这是不可能的。自JPA 2.1和Hibernate 5.0根据this post.
支持select子句中的子查询