Y at-il un moyen d'obtenir la taille de comptage pour une requête nommée JPA avec un jeu de résultats?

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

  •  21-09-2019
  •  | 
  •  

Question

J'aime l'idée de requêtes nommées dans JPA pour les requêtes statiques que je vais faire, mais je veux souvent d'obtenir le résultat du comptage pour la requête ainsi qu'une liste des résultats de certains sous-ensemble de la requête. Je préfère ne pas écrire deux namedqueries presque identiques. Idéalement, ce que je voudrais avoir quelque chose comme:

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

Alors disons que m est 10, s est 0 et il y a 400 lignes de compte. Je me attends r d'avoir une liste de 10 articles dans, mais je voudrais savoir il y a 400 lignes au total. Je pourrais écrire un deuxième @NamedQuery:

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

mais il semble une violation DRY faire que si je suis toujours juste aller à vouloir le compte. Dans ce cas simple, il est facile de garder les deux en phase, mais si les modifications de la requête, il semble moins idéal que je dois mettre à jour les deux @NamedQueries de conserver les valeurs en ligne.

Un cas d'utilisation commune ici serait un sous-ensemble aller chercher des articles, mais qui ont besoin d'une certaine façon d'indiquer nombre total ( « Affichage 1-10 sur 400 »).

Était-ce utile?

La solution

Alors la solution que je fini par utiliser était de créer deux @NamedQuerys, un pour l'ensemble de résultats et un pour le compte, mais la capture de la requête de base dans une chaîne statique pour maintenir sec et veiller à ce que les deux requêtes restent cohérentes. Donc, pour ce qui précède, j'aurais quelque chose comme:

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

De toute évidence, avec cet exemple, le corps de requête est trivial et cela est exagéré. Mais avec des requêtes beaucoup plus complexes, vous vous retrouvez avec une définition unique du corps de requête et peut vous assurer d'avoir les deux requêtes en synchronisation. Vous obtenez également l'avantage que les requêtes sont précompilés et au moins avec EclipseLink, vous obtenez la validation au démarrage au lieu de lorsque vous appelez la requête.

En faisant nommage cohérente entre les deux requêtes, il est possible d'envelopper le corps du code à exécuter les deux ensembles tout en basant le nom de base de la requête.

Autres conseils

Utilisation setFirstResult / setMaxResults do pas retourner un sous-ensemble d'un ensemble de résultats, la requête n'a pas encore été exécuté lorsque vous appelez ces méthodes, ils affectent la requête SELECT générée qui sera exécutée lors de l'appel getResultList . Si vous voulez obtenir le nombre total des dossiers, vous devrez SELECT COUNT vos entités dans une requête distincte (généralement avant pagine).

Pour un exemple complet, consultez Pagination de fichiers de données dans un exemple d'application utilisant JSF, Catalogue Façade Stateless session et Java Persistence API .

oh bien vous pouvez utiliser l'introspection pour obtenir les requêtes nommées annotations comme:

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;
}
Licencié sous: CC-BY-SA avec attribution
Non affilié à StackOverflow
scroll top