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

Posted

技术标签:

【中文标题】有没有办法获取带有结果集的 JPA 命名查询的计数大小?【英文标题】:Is there a way to get the count size for a JPA Named Query with a result set? 【发布时间】:2010-02-17 23:33:32 【问题描述】:

我喜欢 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")

但如果我总是想要计数,这样做似乎违反了 DRY。在这种简单的情况下,很容易使两者保持同步,但如果查询发生变化,我必须同时更新两个 @NamedQueries 以保持值一致,这似乎不太理想。

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

【问题讨论】:

【参考方案1】:

所以我最终使用的解决方案是创建两个@NamedQuery,一个用于结果集,一个用于计数,但在静态字符串中捕获基本查询以保持 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,您可以在启动时而不是在调用查询时获得验证。

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

【讨论】:

有趣,我什至不知道配置注解时可以引用静态finals。但是,我认为不需要两个单独的命名查询的解决方案仍然是理想的。【参考方案2】:

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

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

【讨论】:

是的。我想获得查询将导致的完整计数。因此示例中的计数不对应于 r.size() 或者我会使用它。一个潜在的用例是我想获得一页列出帐户的结果,但为了让他们知道总共有多少页,我想要查询的总计数,即使我只是检索 25 个结果。 @Tim 我已经澄清了我的答案。如果还不清楚,请告诉我。 谢谢。我试图澄清我的问题。基本上,我知道修饰符会在查询运行之前更改它。我希望做的是有一个 @NamedQuery 作为返回子集和获取计数的基础,而不是为计数编写一个查询,为返回集编写一个查询。理想情况下仍然使用@NamedQuery。我会查看您引用的链接。 查看了链接,它显示了我试图避免的问题。基本上,他们在两种不同的方法中有两个不同的查询来获取对象并获取计数。因此,在一个类中,您有“从 Item 中选择 object(o) 作为 o”,在另一个类中,“从 Item 中选择 count(o) 作为 o”。如果您在没有意识到存在相应计数查询的情况下更新前者,您最终会得到不一致的结果。我想在一个地方定义基本查询并派生“object(o)”和“count(o)”变体。如果我使用 String 进行查询,这很容易,但你会失去 Named 的好处。【参考方案3】:

哦,你可以使用自省来获取命名查询注释,例如:

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;

【讨论】:

不确定这如何适用于我的问题。我想使用 NamedQuery 来获得预编译、缓存和其他优化的优势。我希望这两个查询是相同的,除了一个返回结果和一个返回计数。我想遵循 DRY 而不是复制和粘贴条件子句。

以上是关于有没有办法获取带有结果集的 JPA 命名查询的计数大小?的主要内容,如果未能解决你的问题,请参考以下文章

JPA:迭代大型结果集的正确模式是啥?

获取计数并产生一个查询 JPA

jpa命名本机查询无结果

如何删除或更改postgresql上的cakephp分页计数查询?

获取 RESTful 请求看到的返回计数

获取 RESTful 请求看到的返回计数