Contenu du cours
Manipulation des Données Java avec Hibernate
Manipulation des Données Java avec Hibernate
`query()` et `nativeQuery()`
Comme nous l'avons appris dans les chapitres précédents, nous avons des "méthodes intégrées" pour travailler avec les entités. Ces méthodes sont situées dans la Session
. Mais que faire si nous devons écrire une requête spécifique ? Par exemple, nous voulons récupérer uniquement les employés qui ont été embauchés en 2023. Pour une telle requête, nous n'avons pas de fonction intégrée dans la session. Cependant, nous pouvons le faire en utilisant une requête SQL. Cela ressemblera à ceci :
Remarque
Oui, vous pouvez utiliser l'opérateur
BETWEEN
ici, mais je n'aime vraiment pas utiliser cette fonction. Vous pouvez écrire la requête comme vous le souhaitez, tant qu'elle fonctionne correctement.
Super, maintenant nous devons comprendre comment implémenter cela dans le code. Si vous avez examiné les tests dans le chapitre précédent et vu comment ils fonctionnent, vous avez peut-être remarqué que j'ai utilisé une méthode de l'objet session
appelée createNativeQuery()
.
Maintenant, nous allons parler davantage de cette méthode.
Requête Native
La méthode createNativeQuery()
crée une requête SQL, qui est conservée jusqu'à ce que executeUpdate()
ou executeQuery()
soit appelé.
Regardons un exemple où nous devons récupérer des employés qui ont été embauchés dans un délai spécifique.
Tout d'abord, nous devons ajouter cette méthode à l'interface DAO :
Comme vous pouvez le voir, nous utilisons 2 paramètres de type Date
pour spécifier la période exacte qui nous intéresse. Passons maintenant à la classe d'implémentation et implémentons cette méthode.
Pour cela, nous devons :
- Ouvrir une
session
; - Écrire une requête SQL ;
- Utiliser la méthode
createNativeQuery()
où nous utilisons cette requête ; - Ajouter des données des paramètres à ces requêtes pour spécifier la période ;
- Utiliser la méthode
getResultList()
pour récupérer les données de la requête ; - Exécuter la requête et enregistrer le résultat dans une
List
; - Attraper toutes les erreurs potentielles et fermer la session.
Dans l'ensemble, la procédure est très similaire à celle que nous avons effectuée précédemment. Seulement ici, nous utilisons une requête SQL complète pour interagir avec la base de données. Nous avons juste légèrement modifié cette requête pour y définir des paramètres. Eh bien, répétons :
Si nous voulons définir certains paramètres dans la requête SQL, nous écrivons un espace réservé pour ces paramètres directement dans la requête au lieu d'insérer directement les paramètres.
Pour cela, nous utilisons la syntaxe suivante :
Après cela, nous utilisons la méthode setParameter()
où nous utilisons la syntaxe suivante :
De cette manière, Hibernate remplace automatiquement les données des paramètres de la méthode (ou toute autre donnée) directement dans la requête SQL.
Ensuite, nous récupérons une liste avec le type Employee
en utilisant la méthode getResultList()
.
Remarque
La méthode
getResultList()
retournera une liste avec le type que nous avons spécifié dans la méthodecreateNativeQuery()
. Nous avons utiliséEmployee.class
, donc la liste retournée aura ce type. Par exemple, si nous voulons récupérer une liste de noms, nous utilisonsString.class
dans les paramètres.
Ensuite, tout suit l'algorithme, en capturant les erreurs et en fermant la session.
HQL
Hibernate a son propre langage de requête que nous pouvons également utiliser. Il s'appelle HQL (Hibernate Query Language).
HQL est un langage de requête plus pratique que SQL dans le contexte de son utilisation dans le code, mais vous pouvez utiliser n'importe quel langage que vous trouvez pratique.
Considérons les principaux avantages et différences par rapport au SQL :
- Approche orientée objet : HQL travaille avec des objets et leurs propriétés, tandis que SQL travaille avec des tables et des colonnes. Cela signifie qu'en HQL, vous vous référez aux classes et champs dans le code Java, tandis qu'en SQL, vous vous référez aux noms réels des tables et colonnes dans la base de données ;
- Indépendance de la plateforme : HQL isole l'application de la dépendance à une base de données spécifique. Vous pouvez passer d'un SGBD à un autre sans modifier les requêtes HQL, tandis que les requêtes SQL peuvent nécessiter des modifications car différents SGBD peuvent avoir des différences de syntaxe et de fonctions ;
- Navigation par association : En HQL, il est facile de naviguer à travers les objets associés via leurs associations, alors qu'en SQL, vous devez utiliser des jointures de tables ;
- Sécurité des types : HQL offre une sécurité des types car il utilise des classes et propriétés Java, réduisant ainsi les risques d'erreurs liées aux types de données.
Comparons les requêtes effectuées en SQL et HQL pour voir la différence entre ces deux langages de requête :
Requête SQL pour la sélection :
Requête HQL équivalente :
Requête SQL avec JOIN :
Requête HQL équivalente :
Requête SQL pour mise à jour :
Requête HQL équivalente :
Dans ces exemples, on peut voir que HQL n'utilise pas le mot-clé SELECT
pour sélectionner des objets et accéder aux propriétés en utilisant des points, tandis que SQL opère avec les noms de colonnes réels et nécessite l'utilisation du mot-clé SELECT
.
HQL offre une plus grande flexibilité et puissance pour le modèle orienté objet lors du travail avec des bases de données et propose une variété de fonctionnalités pour simplifier le développement, telles que la pagination, les requêtes nommées et l'intégration avec la mise en cache.
Requête
Pour utiliser HQL, nous devrions utiliser la méthode createQuery()
au lieu de createNativeQuery()
.
Modifions la méthode écrite précédemment pour incorporer HQL :
Comme vous pouvez le voir, certains codes ont changé. Maintenant, nous utilisons l'interface Query
au lieu de NativeQuery
. Ces interfaces ont des méthodes presque identiques, donc nous n'avons pas eu à modifier beaucoup la requête. De cette façon, nous opérons sur des objets et voyons clairement quels objets seront récupérés des tables.
Mais comment Hibernate sait-il avec quelle table travailler ?
Hibernate regarde la classe Entity
et voit quelle table y est spécifiée et les colonnes correspondantes de cette table. De cette façon, il substitue automatiquement les données nécessaires et exécute la requête.
Implémentation de la couche de service
Terminons l'implémentation complète de la méthode et implémentons la méthode getEmployeesHiredInASpecificTimeframe()
dans la couche de service.
Tout d'abord, nous devons créer une telle méthode dans l'interface EmployeeService
:
Comme vous pouvez le voir, nous avons ajouté une méthode supplémentaire qui récupérera uniquement les noms des employee
. De même que ce que nous avons fait auparavant, une telle méthode devrait être située dans la couche de service.
Maintenant, regardons l'implémentation :
Dans l'ensemble, un tel code fonctionnera, mais il y a un inconvénient majeur. Il sera très peu pratique pour nous de travailler avec une classe comme Date()
car elle n'accepte aucun format pratique pour nous. Utilisons la classe LocalDate
introduite dans Java 8 pour écrire un analyseur private
qui analysera la date à partir d'un format String
"yyyy-mm-dd" en un objet Date
, le rendant plus pratique pour nous et l'utilisateur de travailler avec les méthodes :
Ce code analysera automatiquement la date de String
à Date
.
Décomposons comment cela fonctionne :
- Nous créons un objet
formatter
de la classeDateTimeFormatter
dans lequel nous spécifions le modèle selon lequel la date sera analysée ; - Ensuite, nous stockons cette date dans une variable de type
LocalDate
, en utilisant la méthodeparse()
et en passant l'objetformatter
en paramètre afin que Java sache exactement quel format de temps nous avons besoin ; - Ensuite, la méthode
atStartOfDay(ZoneId.systemDefault())
convertitLocalDate
enZonedDateTime
au début de la journée dans le fuseau horaire par défaut du système. Cela est nécessaire carLocalDate
ne contient pas d'informations sur l'heure. La méthodetoInstant()
convertitZonedDateTime
enInstant
.Date.from(Instant)
est utilisé pour obtenir un objetDate
à partir deInstant
.
Maintenant, nous devons modifier la méthode pour qu'elle accepte un String
en tant que paramètre, ce qui nous rendra plus pratique de travailler avec.
Tout d'abord, nous devons changer le type de données des paramètres dans la classe d'interface, puis nous procédons à l'édition de l'implémentation :
Voici à quoi ressemblera notre code final. Comme vous pouvez le voir, nous avons utilisé une méthode private
pour convertir la date du format String
au format de la classe d'objet Date
.
Ainsi, pour utiliser cette méthode, nous devons maintenant seulement spécifier la date au format "yyyy-MM-dd". Vérifions la fonctionnalité de ces méthodes dans la méthode main
pour nous assurer que tout fonctionne correctement :
1. Quelle méthode est utilisée pour créer une requête SQL dans Hibernate ?
2. Comment spécifiez-vous les paramètres dans une requête HQL ?
3. Quelle caractéristique distingue HQL de SQL ?
4. Comment l'utilisation de la classe LocalDate
pour les paramètres de date dans les requêtes améliore-t-elle le code ?
Merci pour vos commentaires !