繁体   English   中英

EclipseLink JPQL:任何语句的通用COUNT语句

[英]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.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM