简体   繁体   English

有没有一种方法可以获取带有结果集的JPA命名查询的计数大小?

[英]Is there a way to get the count size for a JPA Named Query with a result set?

I like the idea of Named Queries in JPA for static queries I'm going to do, but I often want to get the count result for the query as well as a result list from some subset of the query. 我喜欢JPA中针对静态查询的命名查询的想法,但是我经常想获取查询的计数结果以及查询的某些子集的结果列表。 I'd rather not write two nearly identical NamedQueries. 我不想写两个几乎相同的NamedQueries。 Ideally, what I'd like to have is something like: 理想情况下,我想要的东西是:

@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();

So let's say m is 10, s is 0 and there are 400 rows in Account. 假设m为10,s为0,并且Account中有400行。 I would expect r to have a list of 10 items in it, but I'd want to know there are 400 rows total. 我希望r中有10个项目的列表,但我想知道总共有400行。 I could write a second @NamedQuery: 我可以写第二个@NamedQuery:

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

but it seems a DRY violation to do that if I'm always just going to want the count. 但是如果我总是只想要计数,那么这样做似乎违反了DRY。 In this simple case it is easy to keep the two in sync, but if the query changes, it seems less than ideal that I have to update both @NamedQueries to keep the values in line. 在这种简单的情况下,使两者保持同步很容易,但是如果查询发生更改,则必须同时更新两个@NamedQueries以使值保持一致似乎不太理想。

A common use case here would be fetching some subset of the items, but needing some way of indicating total count ("Displaying 1-10 of 400"). 这里的一个常见用例是获取项目的某些子集,但需要某种方式来指示总计数(“显示1-10 of 400”)。

So the solution I ended up using was to create two @NamedQuerys, one for the result set and one for the count, but capturing the base query in a static string to maintain DRY and ensure that both queries remain consistent. 因此,我最终使用的解决方案是创建两个@NamedQuerys,一个用于结果集,一个用于计数,但是在静态字符串中捕获基本查询以维护DRY并确保两个查询保持一致。 So for the above, I'd have something like: 因此,对于上面的内容,我会有类似以下内容:

@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();

Obviously, with this example, the query body is trivial and this is overkill. 显然,在此示例中,查询主体是微不足道的,这是过分的。 But with much more complex queries, you end up with a single definition of the query body and can ensure you have the two queries in sync. 但是,对于更复杂的查询,您最终只能得到查询主体的单个定义,并且可以确保两个查询保持同步。 You also get the advantage that the queries are precompiled and at least with Eclipselink, you get validation at startup time instead of when you call the query. 您还获得了查询被预编译的优势,并且至少使用Eclipselink可以在启动时而不是在调用查询时进行验证。

By doing consistent naming between the two queries, it is possible to wrap the body of the code to run both sets just by basing the base name of the query. 通过在两个查询之间进行一致的命名,可以仅基于查询的基本名称来包装代码主体以运行两个集合。

Using setFirstResult / setMaxResults do not return a subset of a result set, the query hasn't even been run when you call these methods, they affect the generated SELECT query that will be executed when calling getResultList . 使用setFirstResult / setMaxResults 不会返回结果集的子集,调用这些方法时甚至没有运行查询,它们会影响生成的SELECT查询,该查询将在调用getResultList时执行。 If you want to get the total records count, you'll have to SELECT COUNT your entities in a separate query (typically before to paginate). 如果要获取总记录数,则必须在单独的查询中SELECT COUNT实体(通常在进行分页之前)。

For a complete example, check out Pagination of Data Sets in a Sample Application using JSF, Catalog Facade Stateless Session, and Java Persistence APIs . 有关完整示例,请使用JSF,Catalog Facade无状态会话和Java Persistence API在示例应用程序中检出数据集的分页

oh well you can use introspection to get named queries annotations like: 哦,您可以使用自省功能来获取命名查询注释,例如:

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;
}

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

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