java - query - jpql join
¿Hay alguna manera de obtener el tamaño de recuento para una consulta con nombre JPA con un conjunto de resultados? (3)
Así que la solución que terminé usando fue crear dos @NamedQuerys, una para el conjunto de resultados y otra para el recuento, pero capturando la consulta base en una cadena estática para mantener DRY y asegurar que ambas consultas permanezcan consistentes. Así que para lo anterior, tendría algo como:
@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();
Obviamente, con este ejemplo, el cuerpo de la consulta es trivial y esto es una exageración. Pero con consultas mucho más complejas, terminas con una sola definición del cuerpo de la consulta y puedes asegurarte de tener las dos consultas sincronizadas. También obtiene la ventaja de que las consultas están precompiladas y, al menos con Eclipselink, obtiene la validación en el momento del inicio en lugar de cuando llama a la consulta.
Al hacer un nombramiento consistente entre las dos consultas, es posible envolver el cuerpo del código para ejecutar ambos conjuntos simplemente basando el nombre base de la consulta.
Me gusta la idea de consultas con nombre en JPA para las consultas estáticas que voy a hacer, pero a menudo quiero obtener el resultado del recuento para la consulta, así como una lista de resultados de algún subconjunto de la consulta. Prefiero no escribir dos NamedQueries casi idénticas. Idealmente, lo que me gustaría tener es algo como:
@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();
Entonces digamos que m es 10, s es 0 y hay 400 filas en Cuenta. Espero que r tenga una lista de 10 elementos, pero me gustaría saber que hay un total de 400 filas. Podría escribir un segundo @NamedQuery:
@NamedQuery(name = "getAccountCount", query = "SELECT COUNT(a) FROM Account")
pero parece una violación SECA hacer eso si siempre voy a querer el conteo. En este simple caso, es fácil mantener los dos sincronizados, pero si la consulta cambia, parece menos que ideal que tengo que actualizar ambos @NamedQueries para mantener los valores en línea.
Un caso de uso común aquí sería obtener un subconjunto de los elementos, pero necesitaría alguna forma de indicar el recuento total ("Mostrando 1-10 de 400").
El uso de setFirstResult
/ setMaxResults
no devuelve un subconjunto de un conjunto de resultados, la consulta ni siquiera se ha ejecutado cuando llama a estos métodos, afectan la consulta SELECT generada que se ejecutará cuando se llame a getResultList
. Si desea obtener el recuento total de registros, deberá SELECT COUNT
sus entidades en una consulta separada (generalmente antes de paginar).
Para ver un ejemplo completo, consulte la Paginación de conjuntos de datos en una aplicación de muestra utilizando JSF, Sesión sin estado de la fachada de catálogo y las API de persistencia de Java .
oh bien, puede utilizar la introspección para obtener anotaciones de consultas con nombre como:
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;
}