![](/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.