我喜欢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”)。
答案 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
您的实体(通常在分页之前)。
答案 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;
}