我喜欢在 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”)。

有帮助吗?

解决方案

所以我结束了使用的解决方案是创建两个@NamedQuerys,一个结果集,一个用于计数,但拍摄静态字符串,以保持干燥,确保这两个查询保持一致的基本查询。因此,针对上述情况,我会碰到这样的:

@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的,你在启动时得到验证,而不是当你调用查询。

通过这样的两个查询之间的一致的命名,有可能只是通过基础查询的基本名称包裹代码运行两组的主体中。

其他提示

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

有关完整的示例,请查看 使用 JSF、Catalog Facade Stateless Session 和 Java Persistence API 对示例应用程序中的数据集进行分页.

哦,你可以用内省来获得命名查询注释,如:

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归因
不隶属于 StackOverflow
scroll top