有没有办法获得结果集的JPA命名查询的计数大小?

时间:2010-02-17 23:33:33

标签: java jpa jpql

我喜欢JPA中的命名查询的想法,我将要做的是静态查询,但我经常想要查询查询的计数结果以及查询的某个子集的结果列表。我宁愿不写两个几乎相同的NamedQueries。理想情况下,我想拥有的是:

@NamedQuery(name = "getAccounts", query = "SELECT a FROM Account")
.
.
  Query q = em.createNamedQuery("getAccounts");
  List r = q.setFirstResult(s).setMaxResults(m).getResultList();
  int count = q.getCount();

因此,假设m为10,s为0且Account中有400行。我希望r有一个包含10个项目的列表,但我想知道总共有400行。我可以写第二个@NamedQuery:

@NamedQuery(name = "getAccountCount", query = "SELECT COUNT(a) FROM Account")

但是,如果我总是想要计算,那么这似乎是一种干扰。在这个简单的情况下,很容易保持两者同步,但是如果查询发生变化,我必须更新@NamedQueries以保持值一致,这似乎不太理想。

这里的常见用例是获取某些项目的子集,但需要某种方式来指示总计数(“显示1-10的400”)。

3 个答案:

答案 0 :(得分:13)

所以我最终使用的解决方案是创建两个@NamedQuerys,一个用于结果集,一个用于计数,但是在静态字符串中捕获基本查询以保持DRY并确保两个查询保持一致。所以对于上面的内容,我会有类似的东西:

@NamedQuery(name = "getAccounts", query = "SELECT a" + accountQuery)
@NamedQuery(name = "getAccounts.count", query = "SELECT COUNT(a)" + accountQuery)
.
static final String accountQuery = " FROM Account";
.
  Query q = em.createNamedQuery("getAccounts");
  List r = q.setFirstResult(s).setMaxResults(m).getResultList();
  int count = ((Long)em.createNamedQuery("getAccounts.count").getSingleResult()).intValue();

显然,在这个例子中,查询体是微不足道的,这是过度的。但是对于更复杂的查询,您最终会得到查询主体的单一定义,并且可以确保您同步这两个查询。您还可以获得预编译查询的优势,至少使用Eclipselink,您可以在启动时进行验证,而不是在调用查询时进行验证。

通过在两个查询之间进行一致的命名,可以通过基于查询的基本名称来包装代码体以运行两个集。

答案 1 :(得分:5)

使用setFirstResult / setMaxResults 返回结果集的子集,当您调用这些方法时,查询甚至都没有运行,它们会影响生成的调用getResultList时将执行的SELECT查询。如果您想获得总记录数,则必须在单独的查询中SELECT COUNT您的实体(通常在分页之前)。

有关完整示例,请查看Pagination of Data Sets in a Sample Application using JSF, Catalog Facade Stateless Session, and Java Persistence APIs

答案 2 :(得分:1)

哦,您可以使用内省来获取命名查询注释,如:

String getNamedQueryCode(Class<? extends Object> clazz, String namedQueryKey) {
    NamedQueries namedQueriesAnnotation = clazz.getAnnotation(NamedQueries.class);
    NamedQuery[] namedQueryAnnotations = namedQueriesAnnotation.value();

    String code = null;
    for (NamedQuery namedQuery : namedQueryAnnotations) {
        if (namedQuery.name().equals(namedQueryKey)) {
            code = namedQuery.query();
            break;
        }
    }

    if (code == null) {
        if (clazz.getSuperclass().getAnnotation(MappedSuperclass.class) != null) {
            code = getNamedQueryCode(clazz.getSuperclass(), namedQueryKey);
        }
    }

    //if not found
    return code;
}