C'è un modo per ottenere la dimensione conteggio per un JPA query denominata con un set di risultati?

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

  •  21-09-2019
  •  | 
  •  

Domanda

Mi piace l'idea di query denominate in JPA per le query statiche ho intenzione di fare, ma spesso mi voglio ottenere il risultato del conteggio per la query, nonché un elenco dei risultati da un sottoinsieme della query. Preferirei non scrivere due NamedQueries quasi identici. Idealmente, ciò che mi piacerebbe avere è qualcosa di simile:

@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();

Quindi diciamo che m è 10, s è 0 e ci sono 400 righe in conto. Mi aspetterei r per avere una lista di 10 elementi in essa contenuti, ma vorrei sapere che ci sono 400 righe totali. Potrei scrivere un secondo @NamedQuery:

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

ma sembra una violazione DRY per farlo se sto sempre e solo andando a voler il conteggio. In questo semplice caso è facile da mantenere i due in sincronia, ma se i cambiamenti di query, sembra tutt'altro che ideale che devo aggiornare entrambi @NamedQueries per mantenere i valori in linea.

Un caso d'uso comune qui sarebbe andare a prendere un sottoinsieme degli elementi, ma che necessitano di un modo di indicare il conteggio totale ( "Visualizzazione 1-10 di 400").

È stato utile?

Soluzione

Quindi la soluzione che ho finito per usare era quello di creare due @NamedQuerys, uno per il set di risultati e una per il conteggio, ma catturando la query di base in una stringa statica per mantenere DRY e garantire che entrambe le query rimangono costanti. Così, per quanto sopra, mi piacerebbe avere qualcosa di simile:

@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();

Ovviamente, con questo esempio, il corpo interrogazione è banale e questo è eccessivo. Ma con molto più complesse query, si finisce con una definizione unica del corpo query e può essere sicuri di avere i due query in sincronia. Si ottiene anche il vantaggio che le query vengono precompilati e almeno con EclipseLink, si ottiene la convalida in tempo di avvio invece che quando si chiama la query.

In questo denominazione coerente tra le due query, è possibile avvolgere il corpo del codice per eseguire entrambi i set solo basando il nome di base della query.

Altri suggerimenti

setFirstResult / setMaxResults do non restituire un sottoinsieme di un set di risultati, la query non è nemmeno stato eseguito quando si chiama questi metodi, influenzano la query SELECT generato che verrà eseguita quando si chiama getResultList . Se si desidera ottenere il conteggio dei record totali, dovrete SELECT COUNT tuoi entità in una query separata (in genere prima di impaginare).

Per un esempio completo, controlla Impaginazione di set di dati in un'applicazione di esempio utilizzando JSF, catalogo Facciata Stateless Session, e Java Persistence API .

vabbè è possibile utilizzare l'introspezione per ottenere query denominate annotazioni come:

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;
}
Autorizzato sotto: CC-BY-SA insieme a attribuzione
Non affiliato a StackOverflow
scroll top