Comment améliorer les recherches avec Apache Deltaspike Data sans écrire du code JPQL? Éléments de réponse.
Introduction
Dans l’article précédent, on a vu comment mettre en œuvre l’accès à la base de données avec Deltaspike Data. Ici nous allons voir comment améliorer les recherches et la gestion des transactions. N’oubliez pas de consulter le fichier zip “ApacheDeltaspikeSkeleton”.
Amélioration des recherches
A partir d’un repository (basé sur FullEntityRepository ou EntityRepository par exemple), on a vu la facilité à écrire des recherches par un ou plusieurs champs, avec retour obligatoire (sous peine de recevoir une exception). C’est bien sûr utile mais plutôt incomplet. Apache Deltaspike propose deux axes d’amélioration:
- le retour optionnel
- la limitation des résultats
Query à retour optionnel
Par exemple, la méthode “abstract User findByLogin(string login)” retournera soit un objet User dont le login est celui demandé soit lèvera une exception. Si de nombreux cas doivent être traités de la sorte, on imagine bien que dans d’autres cas, l’absence d’enregistrement n’est pas une erreur, comme dans le cas d’un processus d’authentification, le login risque de ne pas exister (on pense avoir un compte, on se trompe de login, etc). On va alors introduire la classe “Optional”, ce qui transforme notre méthode comme ceci: “abstract Optional findByLogin(String login)”. L’utilisation se fait alors comme ceci:
Je trouve le code plus lisible avec l’utilisation d’Optional et un peu plus logique quand on sait qu’on peut ne pas avoir de résultat.
Limitation des résultats
Dans la norme JPA, il n’est pas possible de limiter les résultats avec le mot clé SQL “limit”. Impossible donc de trouver 10 enregistrements à partir du 8ème par exemple. Apache DeltaSpike propose une implémentation plutôt bien faite pour contourner ce problème puisqu’il suffit d’ajouter deux paramètres à la méthode: @FirstResult et @MaxResults.
Par exemple, si on veut afficher une liste d’utilisateurs avec pagination, on va ajouter la méthode “abstract Collection findUserOrderByName(@FirstRsultat int start, @MaxResults int max)” et on l’utilisera comme ceci:
1Collection users = this.repository.findUserOrderByName(8, 10);
Problèmes rencontrés
@Query en update
Dans le cadre de mon projet, j’ai dû mettre à jour l’enregistrement de l’utilisateur qui venait de se connecter. Dans mon repository, je disposais d’une première méthode:
Ensuite, pour mettre à jour l’enregistrement, j’ai ajouté cette méthode:
finalement, j’ai agencé le code de cette manière:
Eh bien le code explose avec une erreur de transaction. J’ai testé les options du @Transactional, sans succès. Au final, la solution est d’écrire les méthodes de cette manière:
1@Transactionalabstract Optional findByUserAndActive(String login, Boolean active);
et on l’utilise comme suit:
En gros, impossible de mixer des queries SELECT et UPDATE / DELETE, il faut passer par les méthodes exposées par le repository.
Gestionnaire de transactions non pris en compte
Après avoir configuré la base de données, les repositories et les services (voir épisode 3), tout semblait fonctionner parfaitement, les premières requêtes de type SELECT s’exécutaient sans souci. Mais hélas, lors du premier UPDATE, le gestionnaire de transaction (TransactionManager) indique qu’aucune transaction n’est débutée. C’est un peu la douche froide. Après pas mal de recherches, la solution est finalement plutôt simple puisqu’il faut ajouter une option dans le fichier WEB-INF/beans.xml et annoter les méthodes d’update @Transactional(Transactional.TxType.REQUIRED).
Fichier WEB-INF/beans.xml
Méthode annotée
Conclusion
Apache Deltaspike propose un système de requête bien fait et qui élimine (sans retirer la possibilité) le recours systématique à l’écriture des requêtes JPQL.