java - JPQL:SIZE 函数在 EclipseLink 上导致奇怪的异常

标签 java jpa collections eclipselink jpql

我正在从 Hibernate 移植。 JPQL 语句中的 SIZE 函数有什么问题(假设映射正确)?:

SELECT NEW de.poyry.pqgenerator.view.PqListItem(
 pq.id,
 pq.name,
 pq.submissionDate,
 pe.firstName,
 pe.lastName,
 SIZE(pa))
FROM Prequalification pq
 JOIN pq.user us
 JOIN us.person pe
 LEFT JOIN pq.partnerships pa
 LEFT JOIN pa.company co
GROUP BY pq.id

这是构造函数签名(唯一的构造函数):

public PqListItem(Integer id, String name, Date submissionDate,
                  String ownerFirstName, String ownerLastName,
                  Integer numPartnerships)

查询结果为:

Caused by: Exception [EclipseLink-8023] (Eclipse Persistence Services - 2.3.0.v20110604-r9504): org.eclipse.persistence.exceptions.JPQLException
Exception Description: Syntax error parsing the query [^^...].
Internal Exception: org.eclipse.persistence.internal.libraries.antlr.runtime.EarlyExitException
    at org.eclipse.persistence.exceptions.JPQLException.syntaxError(JPQLException.java:352)
    at org.eclipse.persistence.internal.jpa.parsing.jpql.JPQLParser.handleRecognitionException(JPQLParser.java:354)
    at org.eclipse.persistence.internal.jpa.parsing.jpql.JPQLParser.addError(JPQLParser.java:246)
    at org.eclipse.persistence.internal.jpa.parsing.jpql.JPQLParser.reportError(JPQLParser.java:363)
    at org.eclipse.persistence.internal.jpa.parsing.jpql.antlr.JPQLParser.pathExpression(JPQLParser.java:2894)
    at org.eclipse.persistence.internal.jpa.parsing.jpql.antlr.JPQLParser.collectionValuedPathExpression(JPQLParser.java:2624)
    at org.eclipse.persistence.internal.jpa.parsing.jpql.antlr.JPQLParser.size(JPQLParser.java:7660)
    at org.eclipse.persistence.internal.jpa.parsing.jpql.antlr.JPQLParser.functionsReturningNumerics(JPQLParser.java:6710)
    at org.eclipse.persistence.internal.jpa.parsing.jpql.antlr.JPQLParser.arithmeticPrimary(JPQLParser.java:4762)
    at org.eclipse.persistence.internal.jpa.parsing.jpql.antlr.JPQLParser.arithmeticFactor(JPQLParser.java:4660)
    at org.eclipse.persistence.internal.jpa.parsing.jpql.antlr.JPQLParser.arithmeticTerm(JPQLParser.java:4546)
    at org.eclipse.persistence.internal.jpa.parsing.jpql.antlr.JPQLParser.simpleArithmeticExpression(JPQLParser.java:4462)
    at org.eclipse.persistence.internal.jpa.parsing.jpql.antlr.JPQLParser.scalarExpression(JPQLParser.java:4834)
    at org.eclipse.persistence.internal.jpa.parsing.jpql.antlr.JPQLParser.constructorItem(JPQLParser.java:1980)
    at org.eclipse.persistence.internal.jpa.parsing.jpql.antlr.JPQLParser.constructorExpression(JPQLParser.java:1849)
    at org.eclipse.persistence.internal.jpa.parsing.jpql.antlr.JPQLParser.selectExpression(JPQLParser.java:1300)
    at org.eclipse.persistence.internal.jpa.parsing.jpql.antlr.JPQLParser.selectItem(JPQLParser.java:1169)
    at org.eclipse.persistence.internal.jpa.parsing.jpql.antlr.JPQLParser.selectClause(JPQLParser.java:1081)
    at org.eclipse.persistence.internal.jpa.parsing.jpql.antlr.JPQLParser.selectStatement(JPQLParser.java:359)
    at org.eclipse.persistence.internal.jpa.parsing.jpql.antlr.JPQLParser.document(JPQLParser.java:281)
    at org.eclipse.persistence.internal.jpa.parsing.jpql.JPQLParser.parse(JPQLParser.java:134)
    at org.eclipse.persistence.internal.jpa.parsing.jpql.JPQLParser.buildParseTree(JPQLParser.java:95)
    at org.eclipse.persistence.internal.jpa.EJBQueryImpl.buildEJBQLDatabaseQuery(EJBQueryImpl.java:215)
    at org.eclipse.persistence.internal.jpa.EJBQueryImpl.buildEJBQLDatabaseQuery(EJBQueryImpl.java:190)
    at org.eclipse.persistence.internal.jpa.EJBQueryImpl.<init>(EJBQueryImpl.java:142)
    at org.eclipse.persistence.internal.jpa.EJBQueryImpl.<init>(EJBQueryImpl.java:126)
    at org.eclipse.persistence.internal.jpa.EntityManagerImpl.createQuery(EntityManagerImpl.java:1475)
    ... 139 more
Caused by: org.eclipse.persistence.internal.libraries.antlr.runtime.EarlyExitException
    at org.eclipse.persistence.internal.jpa.parsing.jpql.antlr.JPQLParser.pathExpression(JPQLParser.java:2882)
    ... 161 more

SIZE(pa) 似乎会导致问题。当更改为 SIZE(pq.partnerships) 我得到:

Caused by: Exception [EclipseLink-6137] (Eclipse Persistence Services - 2.3.0.v20110604-r9504): org.eclipse.persistence.exceptions.QueryException
Exception Description: An Exception was thrown while executing a ReportQuery with a constructor expression: java.lang.NoSuchMethodException: de.poyry.pqgenerator.view.PqListItem.<init>(java.lang.Integer, java.lang.String, java.util.Date, java.lang.String, java.lang.String, int)
Query: ReportQuery(referenceClass=Prequalification jpql="SELECT NEW de.poyry.pqgenerator.view.PqListItem(pq.id, pq.name, pq.submissionDate, pe.firstName, pe.lastName, SIZE(pq.partnerships)) FROM Prequalification pq  JOIN pq.user us  JOIN us.person pe  LEFT JOIN pq.partnerships pa  LEFT JOIN pa.company co GROUP BY pq.id")
Default FetchGroup(){id, partnerships, submissionDate, nodes, designSheets, name, statuses, group, user, tendering, isLocked}
    at org.eclipse.persistence.exceptions.QueryException.exceptionWhileUsingConstructorExpression(QueryException.java:494)
    at org.eclipse.persistence.queries.ConstructorReportItem.initialize(ConstructorReportItem.java:188)
    at org.eclipse.persistence.queries.ReportQuery.prepare(ReportQuery.java:1044)
    at org.eclipse.persistence.queries.DatabaseQuery.checkPrepare(DatabaseQuery.java:598)
    at org.eclipse.persistence.queries.ObjectLevelReadQuery.checkPrepare(ObjectLevelReadQuery.java:839)
    at org.eclipse.persistence.queries.DatabaseQuery.prepareCall(DatabaseQuery.java:1719)
    at org.eclipse.persistence.internal.jpa.EJBQueryImpl.buildEJBQLDatabaseQuery(EJBQueryImpl.java:268)
    at org.eclipse.persistence.internal.jpa.EJBQueryImpl.buildEJBQLDatabaseQuery(EJBQueryImpl.java:190)
    at org.eclipse.persistence.internal.jpa.EJBQueryImpl.<init>(EJBQueryImpl.java:142)
    at org.eclipse.persistence.internal.jpa.EJBQueryImpl.<init>(EJBQueryImpl.java:126)
    at org.eclipse.persistence.internal.jpa.EntityManagerImpl.createQuery(EntityManagerImpl.java:1475)
    at org.eclipse.persistence.internal.jpa.EntityManagerImpl.createQuery(EntityManagerImpl.java:1497)
    at com.sun.enterprise.container.common.impl.EntityManagerWrapper.createQuery(EntityManagerWrapper.java:468)
    at de.poyry.pqgenerator.service.PqService.findAllPqs(PqService.java:60)
    at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
    at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:57)
    at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
    at java.lang.reflect.Method.invoke(Method.java:601)
    at org.glassfish.ejb.security.application.EJBSecurityManager.runMethod(EJBSecurityManager.java:1052)
    at org.glassfish.ejb.security.application.EJBSecurityManager.invoke(EJBSecurityManager.java:1124)
    at com.sun.ejb.containers.BaseContainer.invokeBeanMethod(BaseContainer.java:5366)
    at com.sun.ejb.EjbInvocation.invokeBeanMethod(EjbInvocation.java:619)
    at com.sun.ejb.containers.interceptors.AroundInvokeChainImpl.invokeNext(InterceptorManager.java:800)
    at com.sun.ejb.EjbInvocation.proceed(EjbInvocation.java:571)
    at org.jboss.weld.ejb.SessionBeanInterceptor.aroundInvoke(SessionBeanInterceptor.java:46)
    at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
    at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:57)
    at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
    at java.lang.reflect.Method.invoke(Method.java:601)
    at com.sun.ejb.containers.interceptors.AroundInvokeInterceptor.intercept(InterceptorManager.java:861)
    at com.sun.ejb.containers.interceptors.AroundInvokeChainImpl.invokeNext(InterceptorManager.java:800)
    at com.sun.ejb.EjbInvocation.proceed(EjbInvocation.java:571)
    at com.sun.ejb.containers.interceptors.SystemInterceptorProxy.doAround(SystemInterceptorProxy.java:162)
    at com.sun.ejb.containers.interceptors.SystemInterceptorProxy.aroundInvoke(SystemInterceptorProxy.java:144)
    at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
    at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:57)
    at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
    at java.lang.reflect.Method.invoke(Method.java:601)
    at com.sun.ejb.containers.interceptors.AroundInvokeInterceptor.intercept(InterceptorManager.java:861)
    at com.sun.ejb.containers.interceptors.AroundInvokeChainImpl.invokeNext(InterceptorManager.java:800)
    at com.sun.ejb.containers.interceptors.InterceptorManager.intercept(InterceptorManager.java:370)
    at com.sun.ejb.containers.BaseContainer.__intercept(BaseContainer.java:5338)
    at com.sun.ejb.containers.BaseContainer.intercept(BaseContainer.java:5326)
    at com.sun.ejb.containers.EJBLocalObjectInvocationHandler.invoke(EJBLocalObjectInvocationHandler.java:214)
    ... 106 more

看起来没有自动装箱?最后一个构造函数参数的类型是 Integer。奇怪,IMO 应该可以。

有人可以帮忙吗?我在 GlassFish 3.1.1 上使用 EclipseLink 2.3.2。

您如何正确确定查询中的合作伙伴数量? JPA在这里定义了什么?

最佳答案

SIZE 函数在 jpa 规范中定义为

functions_returning_numerics::=
    SIZE(collection_valued_path_expression)

collection_valued_path_expression ::=
    general_identification_variable.{single_valued_object_field.}*collection_valued_field

这意味着您必须将实际属性传递给 SIZE 函数,而不仅仅是变量名。你能试试下面的查询吗:

SELECT NEW de.poyry.pqgenerator.view.PqListItem(
 pq.id,
 pq.name,
 pq.submissionDate,
 pe.firstName,
 pe.lastName,
 SIZE(pq.partnerships))
FROM Prequalification pq
 JOIN pq.user us
 JOIN us.person pe
GROUP BY pq.id, pq.name, pq.submissionDate, pe.firstName, pe.lastName

请注意,我还删除了 pa.companypq.partnerships 的连接,因为它们未被使用,并将非聚合字段添加到 JPA 和 SQL 标准要求的 GROUP BY 表达式。

The requirements for the SELECT clause when GROUP BY is used follow those of SQL: namely, any item that appears in the SELECT clause (other than as an aggregate function or as an argument to an aggregate function) must also appear in the GROUP BY clause.

关于java - JPQL:SIZE 函数在 EclipseLink 上导致奇怪的异常,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/9500163/

相关文章:

java - 尝试使用 JPA 注释保存具有复合键和基本值的映射

python - 如果 collections.defaultdict 不可用怎么办?

使用动态代理的 Java 继承 hack

java - 奇怪的口袋狮身人面像精度下降

java - JEdi​​torPane html 文档内联(嵌入)文件中的图像

forms - symfony2 集合验证器类

javascript - 单击时交换一组元素的 CSS 样式

java - 即使依赖目标失败,Ant 运行目标

java - Hibernate (JPA) 在插入失败时保留分配的 ID

java - 当方法返回 null 时如何在 J-Unit 中进行测试?