![](/img/trans.png)
[英]Invalid query key thrown because of JPQL statement in eclipselink 2.5.2 but works in 2.3.2
[英]EclipseLink JPQL: Generic COUNT statement for any statement
我有一个应用程序,它可以用JPQL
编写非常不同的查询(在不同的资源上)。
对于很多此类查询,我需要知道结果总数(计数),因为我没有应用任何LIMIT
/ OFFSET
由于此查询的性质非常不同,因此无法构建解析器来提取FROM
子句,并且该解析器适用于SELECT COUNT
查询。
让我们来看一个例子:
查询1: SELECT a FROM People a WHERE name = 'John'
查询2: SELECT DISTINCT(o.category.id) FROM Company o
尝试使用标准模式,计数查询将是SELECT(COUNT)z FROM(...)z,在缺少的部分内,我会将完整查询作为2
查询1:从SELECT COUNT(z) FROM (SELECT a FROM People a WHERE name = 'John') z
查询2:从SELECT COUNT(z) FROM (SELECT DISTINCT(o.category.id) FROM Company o) z
从文档中,我可以看到支持FROM子句中的子选择: https : //wiki.eclipse.org/EclipseLink/UserGuide/JPA/Basic_JPA_Development/Querying/JPQL#Sub-selects_in_FROM_clause
这是我编写的示例代码
try {
String subSelect = "SELECT a FROM People a WHERE name = 'John'";
String statement = "SELECT COUNT(z) FROM (" + subSelect + ") z";
TypedQuery<Long> createQuery = em.createQuery(statement, Long.class);
System.out.println(createQuery.getSingleResult().longValue());
} finally {
em.close();
}
但是,如果我尝试执行查询(我正在使用EclipseLink 2.7.0
),则会收到此错误:
java.lang.IllegalArgumentException: An exception occurred while creating a query in EntityManager:
Exception Description: Problem compiling [SELECT COUNT(z) FROM (SELECT a FROM People a WHERE name = 'John') z].
[21, 67] '(SELECT a FROM People a WHERE name = 'John') z' cannot be the first declaration of the FROM clause.
at org.eclipse.persistence.internal.jpa.EntityManagerImpl.createQuery(EntityManagerImpl.java:1743)
at org.eclipse.persistence.internal.jpa.EntityManagerImpl.createQuery(EntityManagerImpl.java:1764)
即使似乎支持子选择, cannot be the first declaration of the FROM clause.
错误很明显。
难道我做错了什么?
我的最终目标是尝试有一个标准的COUNT
查询,我可以将其用于任何类型的语句,只需使用COUNT(*) FROM (..statement..)
,这样实现非常通用。
或者,如果有可以实现相同目标的方法,则也很有用。
编辑
还尝试COUNT(0)' as suggested, like this:
使用COUNT(0)' as suggested, like this:
SELECT COUNT(0)FROM(SELECT DISTINCT(o.category.id)FROM Company o)`
Exception Description: Syntax error parsing [SELECT COUNT(0) FROM (SELECT DISTINCT(o.category.id) FROM Company o)].
[68, 68] An identification variable must be provided for a range variable declaration.
在@chris的建议下,我提出了以下解决方案
/**
* https://stackoverflow.com/a/43933889/1013317
*/
private static String queryToSqlString(EntityManager em, Query query) {
Session session = em.unwrap(JpaEntityManager.class).getActiveSession();
DatabaseQuery databaseQuery = query.unwrap(EJBQueryImpl.class).getDatabaseQuery();
databaseQuery.prepareCall(session, new DatabaseRecord());
Record r = databaseQuery.getTranslationRow();
// Query with parameters
return databaseQuery.getTranslatedSQLString(session, r);
}
/**
* Overload, see {@link #queryToSqlString(EntityManager, Query)}
*/
private static String queryToSqlString(EntityManager em, String statement) {
return queryToSqlString(em, em.createQuery(statement));
}
/**
* Count the amount of results for a given statement
*/
private static long count(EntityManager em, Query query) {
String countStatement = String.format("SELECT COUNT(*) FROM (%s) AS t", queryToSqlString(em, query));
Query createNativeQuery = em.createNativeQuery(countStatement);
return (long) createNativeQuery.getSingleResult();
}
/**
* Overload, see {@link #count(EntityManager, Query)}
*/
private static long count(EntityManager em, String statement) {
return count(em, em.createQuery(statement));
}
我尝试了几个查询(简单查询,联接查询等),它似乎工作得很好。 另外,生成SQL字符串时,最终应用于查询对象的LIMIT或OFFSET会被忽略,因此我什至不需要从生成的语句中删除它。
queryToSqlString
还可以非常方便地记录提交给DBMS的本机语句(如果您不想启用完整的EclipseLink记录)
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.