JPQL

时间:2019-03-05 07:31:39

标签: java jpa jpql

我在将SQL查询转换为JPQL时遇到问题。有一个表CASE_FORM,其状态可以是“ NEW”,“ Draft”等。另外三列:category,case_type和region(即location)。我的任务是显示类别,case_type和区域的每种组合的每个case_status的案例数。

例如,对于某些类别: A ,案例类型: 1 和区域:旧金山,状态为的案例数新可以是一些整数值,例如12,状态为草稿的案例数可以是3。

为此,我打算在类别,case_type和region上使用分组依据,然后对具有case_status 草稿的案件数进行计数,并为另一个具有状态 New的案件进行计数

下面给出了上述方法的有效SQL查询:

  

SQL:

select cf.CATEGORY_ID, cf.CASE_TYPE_ID, cf.REGION,
(select count(*) from KM_ECM.CASE_FORM where CATEGORY_ID=cf.CATEGORY_ID AND CASE_TYPE_ID=cf.CASE_TYPE_ID AND REGION=cf.REGION AND CASE_STATUS='New') AS NEW,
(select count(*) from KM_ECM.CASE_FORM where CATEGORY_ID=cf.CATEGORY_ID AND CASE_TYPE_ID=cf.CASE_TYPE_ID AND REGION=cf.REGION AND CASE_STATUS='Draft') AS DRAFT
from KM_ECM.CASE_FORM cf
group by cf.CATEGORY_ID, cf.CASE_TYPE_ID, cf.REGION;

由于查询将在基于Java的Web服务中命中,因此我使用的是JPA,因此使用JPQL编写上述查询。对于此特定任务,JPQL中的查询如下所示:

  

JPQL:

@NamedQuery(name="CaseForm.getMainReportData", query="SELECT new com.techlogix.sbp.casemanagement.model.MainReport(c.category, c.caseType, c.region, "
        + "(SELECT count(v) FROM CaseForm v where v.category=c.category AND v.caseType=c.caseType AND v.region=c.region AND v.caseStatus='New'),"
        + "(SELECT count(v) FROM CaseForm v where v.category=c.category AND v.caseType=c.caseType AND v.region=c.region AND v.caseStatus='Draft')"
        + ") "
        + "FROM CaseForm c "
        + "GROUP BY c.category, c.caseType, c.region")

JPQL查询背后的思想与上面提到的SQL完全相同。唯一的补充是JPQL查询将数据存储在自定义Bean类 MainReport 中。

但是,执行后查询会中断并引发以下异常,

  

org.apache.openjpa.persistence.ArgumentException :您的查询无效。您的select和have子句必须仅包含也出现在分组子句中的汇总或值

该异常的完整堆栈跟踪为:

[3/5/19 12:17:05:718 PKT] 000000c0 BusinessExcep E   CNTR0020E: EJB threw an unexpected (non-declared) exception during invocation of method "getMainReport" on bean "BeanId(casemanagement-ear#casemanagement-business-service-impl-1.0.jar#FEODReportService, null)". Exception data: <openjpa-2.2.3-SNAPSHOT-r422266:1764177 nonfatal user error> org.apache.openjpa.persistence.ArgumentException: Your query on type "class com.techlogix.sbp.casemanagement.model.CaseForm" with filter "" is invalid.  Your select and having clauses must only include aggregates or values that also appear in your grouping clause.
at org.apache.openjpa.kernel.ExpressionStoreQuery$AbstractExpressionExecutor$ValidateGroupingExpressionVisitor.enter(ExpressionStoreQuery.java:563)
at org.apache.openjpa.kernel.exps.Val.acceptVisit(Val.java:119)
at org.apache.openjpa.jdbc.kernel.exps.CompareEqualExpression.acceptVisit(CompareEqualExpression.java:138)
at org.apache.openjpa.jdbc.kernel.exps.AndExpression.acceptVisit(AndExpression.java:80)
at org.apache.openjpa.jdbc.kernel.exps.SubQ.acceptVisit(SubQ.java:241)
at org.apache.openjpa.kernel.ExpressionStoreQuery$AbstractExpressionExecutor$ValidateGroupingExpressionVisitor.validate(ExpressionStoreQuery.java:544)
at org.apache.openjpa.kernel.ExpressionStoreQuery$AbstractExpressionExecutor.validate(ExpressionStoreQuery.java:335)
at org.apache.openjpa.kernel.QueryImpl.compile(QueryImpl.java:591)
at org.apache.openjpa.persistence.EntityManagerImpl.createNamedQuery(EntityManagerImpl.java:1038)
at com.ibm.ws.persistence.EntityManagerImpl.createNamedQuery(EntityManagerImpl.java:116)
at com.ibm.ws.persistence.EntityManagerImpl.createNamedQuery(EntityManagerImpl.java:50)
at org.apache.openjpa.persistence.EntityManagerImpl.createNamedQuery(EntityManagerImpl.java:1017)
at com.ibm.ws.persistence.EntityManagerImpl.createNamedQuery(EntityManagerImpl.java:127)
at com.ibm.ws.jpa.management.JPATxEmInvocation.createNamedQuery(JPATxEmInvocation.java:340)
at com.ibm.ws.jpa.management.JPAEntityManager.createNamedQuery(JPAEntityManager.java:543)
at com.techlogix.sbp.casemanagement.dao.impl.CaseFormDaoImpl.getMainReportData(CaseFormDaoImpl.java:495)
at com.techlogix.sbp.casemanagement.service.impl.FEODReportServiceImpl.getMainReport(FEODReportServiceImpl.java:171)
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:95)
at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:55)
at java.lang.reflect.Method.invoke(Method.java:508)
at com.ibm.ejs.container.EJSContainer.invokeProceed(EJSContainer.java:5798)
at com.ibm.ejs.container.interceptors.InvocationContextImpl.proceed(InvocationContextImpl.java:569)
at org.apache.webbeans.ejb.common.interceptor.OpenWebBeansEjbInterceptor.callInterceptorsAndDecorators(OpenWebBeansEjbInterceptor.java:559)
at org.apache.webbeans.ejb.common.interceptor.OpenWebBeansEjbInterceptor.callToOwbInterceptors(OpenWebBeansEjbInterceptor.java:222)
at sun.reflect.GeneratedMethodAccessor16.invoke(Unknown Source)
at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:55)
at java.lang.reflect.Method.invoke(Method.java:508)
at com.ibm.ejs.container.interceptors.InterceptorProxy.invokeInterceptor(InterceptorProxy.java:227)
at com.ibm.ejs.container.interceptors.InvocationContextImpl.proceed(InvocationContextImpl.java:549)
at org.apache.webbeans.ejb.WSEJBInterceptor.callToOwbInterceptors(WSEJBInterceptor.java:152)
at sun.reflect.GeneratedMethodAccessor13.invoke(Unknown Source)
at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:55)
at java.lang.reflect.Method.invoke(Method.java:508)
at com.ibm.ejs.container.interceptors.InterceptorProxy.invokeInterceptor(InterceptorProxy.java:227)
at com.ibm.ejs.container.interceptors.InvocationContextImpl.proceed(InvocationContextImpl.java:549)
at com.ibm.ejs.container.interceptors.InvocationContextImpl.doAroundInvoke(InvocationContextImpl.java:230)
at com.ibm.ejs.container.EJSContainer.invoke(EJSContainer.java:5689)
at com.techlogix.sbp.casemanagement.service.EJSRemote0SLFEODReportService_81b95711.getMainReport(EJSRemote0SLFEODReportService_81b95711.java)
at com.techlogix.sbp.casemanagement.service._FEODReportService_Stub.getMainReport(_FEODReportService_Stub.java:1)
at com.techlogix.sbp.casemanagement.soap.FEODReportsWebService.getMainReport(FEODReportsWebService.java:120)
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:95)
at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:55)
at java.lang.reflect.Method.invoke(Method.java:508)
at org.apache.axis2.jaxws.server.dispatcher.JavaDispatcher.invokeTargetOperation(JavaDispatcher.java:120)
at org.apache.axis2.jaxws.server.dispatcher.JavaBeanDispatcher.invoke(JavaBeanDispatcher.java:118)
at org.apache.axis2.jaxws.server.EndpointController.invoke(EndpointController.java:111)
at org.apache.axis2.jaxws.server.JAXWSMessageReceiver.receive(JAXWSMessageReceiver.java:161)
at org.apache.axis2.engine.AxisEngine.receive(AxisEngine.java:212)
at org.apache.axis2.transport.http.HTTPTransportUtils.processHTTPPostRequest(HTTPTransportUtils.java:172)
at com.ibm.ws.websvcs.transport.http.WASAxis2Servlet.doPost(WASAxis2Servlet.java:1632)
at javax.servlet.http.HttpServlet.service(HttpServlet.java:595)
at javax.servlet.http.HttpServlet.service(HttpServlet.java:668)
at com.ibm.ws.webcontainer.servlet.ServletWrapper.service(ServletWrapper.java:1233)
at com.ibm.ws.webcontainer.servlet.ServletWrapper.handleRequest(ServletWrapper.java:782)
at com.ibm.ws.webcontainer.servlet.ServletWrapper.handleRequest(ServletWrapper.java:481)
at com.ibm.ws.webcontainer.servlet.ServletWrapperImpl.handleRequest(ServletWrapperImpl.java:178)
at com.ibm.ws.webcontainer.filter.WebAppFilterManager.invokeFilters(WebAppFilterManager.java:1114)
at com.ibm.ws.webcontainer.servlet.CacheServletWrapper.handleRequest(CacheServletWrapper.java:87)
at com.ibm.ws.webcontainer.WebContainer.handleRequest(WebContainer.java:949)
at com.ibm.ws.webcontainer.WSWebContainer.handleRequest(WSWebContainer.java:1817)
at com.ibm.ws.webcontainer.channel.WCChannelLink.ready(WCChannelLink.java:200)
at com.ibm.ws.http.channel.inbound.impl.HttpInboundLink.handleDiscrimination(HttpInboundLink.java:463)
at com.ibm.ws.http.channel.inbound.impl.HttpInboundLink.handleNewRequest(HttpInboundLink.java:530)
at com.ibm.ws.http.channel.inbound.impl.HttpInboundLink.processRequest(HttpInboundLink.java:316)
at com.ibm.ws.http.channel.inbound.impl.HttpInboundLink.ready(HttpInboundLink.java:287)
at com.ibm.ws.tcp.channel.impl.NewConnectionInitialReadCallback.sendToDiscriminators(NewConnectionInitialReadCallback.java:214)
at com.ibm.ws.tcp.channel.impl.NewConnectionInitialReadCallback.complete(NewConnectionInitialReadCallback.java:113)
at com.ibm.ws.tcp.channel.impl.AioReadCompletionListener.futureCompleted(AioReadCompletionListener.java:175)
at com.ibm.io.async.AbstractAsyncFuture.invokeCallback(AbstractAsyncFuture.java:217)
at com.ibm.io.async.AsyncChannelFuture.fireCompletionActions(AsyncChannelFuture.java:161)
at com.ibm.io.async.AsyncFuture.completed(AsyncFuture.java:138)
at com.ibm.io.async.ResultHandler.complete(ResultHandler.java:204)
at com.ibm.io.async.ResultHandler.runEventProcessingLoop(ResultHandler.java:775)
at com.ibm.io.async.ResultHandler$2.run(ResultHandler.java:905)
at com.ibm.ws.util.ThreadPool$Worker.run(ThreadPool.java:1892)


[3/5/19 12:17:05:733 PKT] 000000c0 AxisEngine    E org.apache.axis2.engine.AxisEngine receive null
                             org.apache.axis2.AxisFault
at org.apache.axis2.jaxws.server.dispatcher.JavaBeanDispatcher.createFaultResponse(JavaBeanDispatcher.java:407)
at org.apache.axis2.jaxws.server.dispatcher.JavaBeanDispatcher.invoke(JavaBeanDispatcher.java:138)
at org.apache.axis2.jaxws.server.EndpointController.invoke(EndpointController.java:111)
at org.apache.axis2.jaxws.server.JAXWSMessageReceiver.receive(JAXWSMessageReceiver.java:161)
at org.apache.axis2.engine.AxisEngine.receive(AxisEngine.java:212)
at org.apache.axis2.transport.http.HTTPTransportUtils.processHTTPPostRequest(HTTPTransportUtils.java:172)
at com.ibm.ws.websvcs.transport.http.WASAxis2Servlet.doPost(WASAxis2Servlet.java:1632)
at javax.servlet.http.HttpServlet.service(HttpServlet.java:595)
at javax.servlet.http.HttpServlet.service(HttpServlet.java:668)
at com.ibm.ws.webcontainer.servlet.ServletWrapper.service(ServletWrapper.java:1233)
at com.ibm.ws.webcontainer.servlet.ServletWrapper.handleRequest(ServletWrapper.java:782)
at com.ibm.ws.webcontainer.servlet.ServletWrapper.handleRequest(ServletWrapper.java:481)
at com.ibm.ws.webcontainer.servlet.ServletWrapperImpl.handleRequest(ServletWrapperImpl.java:178)
at com.ibm.ws.webcontainer.filter.WebAppFilterManager.invokeFilters(WebAppFilterManager.java:1114)
at com.ibm.ws.webcontainer.servlet.CacheServletWrapper.handleRequest(CacheServletWrapper.java:87)
at com.ibm.ws.webcontainer.WebContainer.handleRequest(WebContainer.java:949)
at com.ibm.ws.webcontainer.WSWebContainer.handleRequest(WSWebContainer.java:1817)
at com.ibm.ws.webcontainer.channel.WCChannelLink.ready(WCChannelLink.java:200)
at com.ibm.ws.http.channel.inbound.impl.HttpInboundLink.handleDiscrimination(HttpInboundLink.java:463)
at com.ibm.ws.http.channel.inbound.impl.HttpInboundLink.handleNewRequest(HttpInboundLink.java:530)
at com.ibm.ws.http.channel.inbound.impl.HttpInboundLink.processRequest(HttpInboundLink.java:316)
at com.ibm.ws.http.channel.inbound.impl.HttpInboundLink.ready(HttpInboundLink.java:287)
at com.ibm.ws.tcp.channel.impl.NewConnectionInitialReadCallback.sendToDiscriminators(NewConnectionInitialReadCallback.java:214)
at com.ibm.ws.tcp.channel.impl.NewConnectionInitialReadCallback.complete(NewConnectionInitialReadCallback.java:113)
at com.ibm.ws.tcp.channel.impl.AioReadCompletionListener.futureCompleted(AioReadCompletionListener.java:175)
at com.ibm.io.async.AbstractAsyncFuture.invokeCallback(AbstractAsyncFuture.java:217)
at com.ibm.io.async.AsyncChannelFuture.fireCompletionActions(AsyncChannelFuture.java:161)
at com.ibm.io.async.AsyncFuture.completed(AsyncFuture.java:138)
at com.ibm.io.async.ResultHandler.complete(ResultHandler.java:204)
at com.ibm.io.async.ResultHandler.runEventProcessingLoop(ResultHandler.java:775)
at com.ibm.io.async.ResultHandler$2.run(ResultHandler.java:905)
at com.ibm.ws.util.ThreadPool$Worker.run(ThreadPool.java:1892)
Caused by: java.lang.reflect.InvocationTargetException
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:95)
at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:55)
at java.lang.reflect.Method.invoke(Method.java:508)
at org.apache.axis2.jaxws.server.dispatcher.JavaDispatcher.invokeTargetOperation(JavaDispatcher.java:120)
at org.apache.axis2.jaxws.server.dispatcher.JavaBeanDispatcher.invoke(JavaBeanDispatcher.java:118)
... 30 more
Caused by: javax.ejb.EJBException: See nested exception; nested exception is: <openjpa-2.2.3-SNAPSHOT-r422266:1764177 nonfatal user error> org.apache.openjpa.persistence.ArgumentException: Your query on type "class com.techlogix.sbp.casemanagement.model.CaseForm" with filter "SELECT new com.techlogix.sbp.casemanagement.model.MainReport(c.category, c.caseType, c.region, (SELECT count(v) FROM CaseForm v where v.category=c.category AND v.caseType=c.caseType AND v.region=c.region AND v.caseStatus='New'), (SELECT count(v) FROM CaseForm v where v.category=c.category AND v.caseType=c.caseType AND v.region=c.region AND v.caseStatus='Draft')) FROM CaseForm c GROUP BY c.category, c.caseType, c.region" is invalid.  Your select and having clauses must only include aggregates or values that also appear in your grouping clause.
at com.ibm.ejs.container.util.ExceptionUtil.EJBException(ExceptionUtil.java:475)
at com.ibm.ejs.container.util.ExceptionUtil.EJBException(ExceptionUtil.java:365)
at com.ibm.ejs.container.BusinessExceptionMappingStrategy.mapException(BusinessExceptionMappingStrategy.java:392)
at com.ibm.ejs.container.BusinessExceptionMappingStrategy.setUncheckedException(BusinessExceptionMappingStrategy.java:554)
at com.ibm.ejs.container.EJSDeployedSupport.setUncheckedLocalException(EJSDeployedSupport.java:570)
at com.techlogix.sbp.casemanagement.service.EJSRemote0SLFEODReportService_81b95711.getMainReport(EJSRemote0SLFEODReportService_81b95711.java)
at com.techlogix.sbp.casemanagement.service._FEODReportService_Stub.getMainReport(_FEODReportService_Stub.java:1)
at com.techlogix.sbp.casemanagement.soap.FEODReportsWebService.getMainReport(FEODReportsWebService.java:120)
... 36 more
Caused by: <openjpa-2.2.3-SNAPSHOT-r422266:1764177 nonfatal user error> org.apache.openjpa.persistence.ArgumentException: Your query on type "class com.techlogix.sbp.casemanagement.model.CaseForm" with filter "SELECT new com.techlogix.sbp.casemanagement.model.MainReport(c.category, c.caseType, c.region, (SELECT count(v) FROM CaseForm v where v.category=c.category AND v.caseType=c.caseType AND v.region=c.region AND v.caseStatus='New'), (SELECT count(v) FROM CaseForm v where v.category=c.category AND v.caseType=c.caseType AND v.region=c.region AND v.caseStatus='Draft')) FROM CaseForm c GROUP BY c.category, c.caseType, c.region" is invalid.  Your select and having clauses must only include aggregates or values that also appear in your grouping clause.
at org.apache.openjpa.kernel.ExpressionStoreQuery$AbstractExpressionExecutor$ValidateGroupingExpressionVisitor.enter(ExpressionStoreQuery.java:563)
at org.apache.openjpa.kernel.exps.Val.acceptVisit(Val.java:119)
at org.apache.openjpa.jdbc.kernel.exps.CompareEqualExpression.acceptVisit(CompareEqualExpression.java:138)
at org.apache.openjpa.jdbc.kernel.exps.AndExpression.acceptVisit(AndExpression.java:80)
at org.apache.openjpa.jdbc.kernel.exps.SubQ.acceptVisit(SubQ.java:241)
at org.apache.openjpa.kernel.ExpressionStoreQuery$AbstractExpressionExecutor$ValidateGroupingExpressionVisitor.validate(ExpressionStoreQuery.java:544)
at org.apache.openjpa.kernel.ExpressionStoreQuery$AbstractExpressionExecutor.validate(ExpressionStoreQuery.java:335)
at org.apache.openjpa.kernel.QueryImpl.compile(QueryImpl.java:591)
at org.apache.openjpa.persistence.EntityManagerImpl.createNamedQuery(EntityManagerImpl.java:1038)
at com.ibm.ws.persistence.EntityManagerImpl.createNamedQuery(EntityManagerImpl.java:116)
at com.ibm.ws.persistence.EntityManagerImpl.createNamedQuery(EntityManagerImpl.java:50)
at org.apache.openjpa.persistence.EntityManagerImpl.createNamedQuery(EntityManagerImpl.java:1017)
at com.ibm.ws.persistence.EntityManagerImpl.createNamedQuery(EntityManagerImpl.java:127)
at com.ibm.ws.jpa.management.JPATxEmInvocation.createNamedQuery(JPATxEmInvocation.java:340)
at com.ibm.ws.jpa.management.JPAEntityManager.createNamedQuery(JPAEntityManager.java:543)
at com.techlogix.sbp.casemanagement.dao.impl.CaseFormDaoImpl.getMainReportData(CaseFormDaoImpl.java:495)
at com.techlogix.sbp.casemanagement.service.impl.FEODReportServiceImpl.getMainReport(FEODReportServiceImpl.java:171)
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:95)
at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:55)
at java.lang.reflect.Method.invoke(Method.java:508)
at com.ibm.ejs.container.EJSContainer.invokeProceed(EJSContainer.java:5798)
at com.ibm.ejs.container.interceptors.InvocationContextImpl.proceed(InvocationContextImpl.java:569)
at org.apache.webbeans.ejb.common.interceptor.OpenWebBeansEjbInterceptor.callInterceptorsAndDecorators(OpenWebBeansEjbInterceptor.java:559)
at org.apache.webbeans.ejb.common.interceptor.OpenWebBeansEjbInterceptor.callToOwbInterceptors(OpenWebBeansEjbInterceptor.java:222)
at sun.reflect.GeneratedMethodAccessor16.invoke(Unknown Source)
at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:55)
at java.lang.reflect.Method.invoke(Method.java:508)
at com.ibm.ejs.container.interceptors.InterceptorProxy.invokeInterceptor(InterceptorProxy.java:227)
at com.ibm.ejs.container.interceptors.InvocationContextImpl.proceed(InvocationContextImpl.java:549)
at org.apache.webbeans.ejb.WSEJBInterceptor.callToOwbInterceptors(WSEJBInterceptor.java:152)
at sun.reflect.GeneratedMethodAccessor13.invoke(Unknown Source)
at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:55)
at java.lang.reflect.Method.invoke(Method.java:508)
at com.ibm.ejs.container.interceptors.InterceptorProxy.invokeInterceptor(InterceptorProxy.java:227)
at com.ibm.ejs.container.interceptors.InvocationContextImpl.proceed(InvocationContextImpl.java:549)
at com.ibm.ejs.container.interceptors.InvocationContextImpl.doAroundInvoke(InvocationContextImpl.java:230)
at com.ibm.ejs.container.EJSContainer.invoke(EJSContainer.java:5689)
... 39 more

1 个答案:

答案 0 :(得分:0)

我建议您不要运行两个非常相似的相关子查询。在SQL中一次性计算两个计数将更快。鉴于您的子查询是从与外部查询相同的表中选择的,您甚至可以通过单次访问表来完成此操作:

SELECT
  cf.CATEGORY_ID, 
  cf.CASE_TYPE_ID, 
  cf.REGION,
  COUNT(CASE WHEN cf.CASE_STATUS = 'New' THEN 1 END) AS NEW,
  COUNT(CASE WHEN cf.CASE_STATUS = 'Draft' THEN 1 END) AS DRAFT
FROM KM_ECM.CASE_FORM cf
GROUP BY 
  cf.CATEGORY_ID, 
  cf.CASE_TYPE_ID, 
  cf.REGION

I have blogged about this technique more in detail here

有了这个不再依赖于相关子查询的简化版本,您现在可以在JPQL中使用DTO投影,或者您可以只使用本机查询。