【问题标题】:JPQL: SIZE function causing strange exceptions on EclipseLinkJPQL:在 EclipseLink 上导致奇怪异常的 SIZE 函数
【发布时间】:2012-03-19 00:00:39
【问题描述】:

我从 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

看起来好像没有自动装箱?最后一个构造函数参数的类型是整数。奇怪,它应该可以在 IMO 中使用。

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

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

【问题讨论】:

    标签: java jpa collections eclipselink jpql


    【解决方案1】:

    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 表达式。

    使用GROUP BYSELECT子句的要求遵循SQL的要求:即任意 出现在 SELECT 子句中的项目(除了作为聚合函数或作为 聚合函数)也必须出现在GROUP BY 子句中。

    【讨论】:

    • 我只是不明白为什么我需要 GROUP BY 中的 , pq.name, pq.submissionDate, pe.firstName, pe.lastName 字段,因为只有 pq.id 产生相同的 PQ 项目列表。
    【解决方案2】:

    如果您添加一个采用 int 而不是 Integer 的构造函数,它会起作用吗? 这似乎是问题所在。

    我认为这在 EclipseLink 2.4 流中已修复,Integer 或 int 现在应该可以工作了。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2012-04-02
      • 2016-06-21
      • 1970-01-01
      • 1970-01-01
      • 2023-02-24
      • 1970-01-01
      • 2016-01-18
      相关资源
      最近更新 更多