¿Hay una manera de conseguir el tamaño recuento para una consulta con nombre APP con un conjunto de resultados?

StackOverflow https://stackoverflow.com/questions/2285270

  •  21-09-2019
  •  | 
  •  

Pregunta

Me gusta la idea de consultas con nombre en JPA para consultas estáticas que voy a hacer, pero a menudo quieren obtener el resultado de la cuenta para la consulta, así como una lista de resultados de algún subconjunto de la consulta. Yo prefiero no escribir dos NamedQueries casi idénticos. 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();

Así que digamos que m es 10, s es 0 y hay 400 filas en cuenta. Yo esperaría a r tiene una lista de 10 elementos en ella, pero me gustaría saber hay 400 filas totales. Podría escribir un segundo @NamedQuery:

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

pero parece una violación DRY para hacer eso si estoy siempre solo va a querer el recuento. En este caso simple que es fácil de mantener los dos en sincronía, pero si los cambios de consulta, parece menos que ideal que tengo para actualizar ambos @NamedQueries para mantener los valores de la fila.

Un caso de uso común aquí sería ir a buscar algún subconjunto de los artículos, pero que necesitan alguna forma de indicar recuento total ( "Viendo 1-10 de 400").

¿Fue útil?

Solución

Así que la solución que terminé usando era crear dos @NamedQuerys, uno para el conjunto de resultados y otro para el recuento, pero la captura de la consulta de base en una cadena estática para mantener seco y asegurar que tanto las consultas siguen siendo coherentes. Así que por 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 las consultas mucho más complejas, se termina con una definición única del cuerpo de la consulta y puede asegurarse de que tiene las dos consultas en sincronía. También tendrá la ventaja de que las consultas están precompilados y por lo menos con EclipseLink, se obtiene la validación en tiempo de inicio en lugar de cuando se llama a la consulta.

Al hacer nomenclatura coherente entre las dos consultas, es posible envolver el cuerpo del código para ejecutar ambos conjuntos simplemente basando el nombre de la base de la consulta.

Otros consejos

Uso setFirstResult / setMaxResults Do no devolver un subconjunto de un conjunto de resultados, la consulta aún no se ha ejecutado cuando se llama a estos métodos, que afectan a la consulta SELECT generada que se ejecutará cuando se llama getResultList . Si desea obtener cuentan los registros totales, que tendrá que SELECT COUNT sus entidades en una consulta independiente (por lo general antes de paginar).

En un ejemplo completo, visita Paginación de conjuntos de datos en una aplicación de ejemplo usando JSF, Catálogo Fachada de sesión sin estado, y Java Persistence API .

oh bien puede utilizar la introspección para obtener consultas con nombre anotaciones 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;
}
Licenciado bajo: CC-BY-SA con atribución
No afiliado a StackOverflow
scroll top