Requête nommée Hibernate

1. Vue d'ensemble

Un inconvénient majeur de la dispersion de HQL et SQL sur les objets d'accès aux données est que cela rend le code illisible. Par conséquent, il peut être judicieux de regrouper tous les HQL et SQL en un seul endroit et d'utiliser uniquement leur référence dans le code d'accès aux données réel. Heureusement, Hibernate nous permet de faire cela avec des requêtes nommées.

Une requête nommée est une requête définie de manière statique avec une chaîne de requête non modifiable prédéfinie. Ils sont validés lors de la création de la fabrique de sessions, ce qui fait que l'application échoue rapidement en cas d'erreur.

Dans cet article, nous verrons comment définir et utiliser les requêtes nommées Hibernate à l'aide des annotations @NamedQuery et @NamedNativeQuery .

2. L'entité

Examinons d'abord l'entité que nous utiliserons dans cet article:

@Entity public class DeptEmployee { @Id @GeneratedValue(strategy = GenerationType.SEQUENCE) private long id; private String employeeNumber; private String designation; private String name; @ManyToOne private Department department; // getters and setters }

Dans notre exemple, nous allons récupérer un employé en fonction de son numéro d'employé.

3. Requête nommée

Pour définir cela comme une requête nommée, nous utiliserons l' annotation org.hibernate.annotations.NamedQuery . Il étend le javax .persistence.NamedQuery avec les fonctionnalités Hibernate.

Nous le définirons comme une annotation de la classe DeptEmployee :

@org.hibernate.annotations.NamedQuery(name = "DeptEmployee_findByEmployeeNumber", query = "from DeptEmployee where employeeNumber = :employeeNo") 

Il est important de noter que chaque annotation @NamedQuery est attachée à exactement une classe d'entité ou une superclasse mappée. Mais, comme la portée des requêtes nommées est l'unité de persistance entière, nous devons sélectionner le nom de la requête avec soin pour éviter une collision. Et nous y sommes parvenus en utilisant le nom de l'entité comme préfixe.

Si nous avons plus d'une requête nommée pour une entité, nous utiliserons l' annotation @NamedQueries pour les regrouper:

@org.hibernate.annotations.NamedQueries({ @org.hibernate.annotations.NamedQuery(name = "DeptEmployee_FindByEmployeeNumber", query = "from DeptEmployee where employeeNumber = :employeeNo"), @org.hibernate.annotations.NamedQuery(name = "DeptEmployee_FindAllByDesgination", query = "from DeptEmployee where designation = :designation"), @org.hibernate.annotations.NamedQuery(name = "DeptEmployee_UpdateEmployeeDepartment", query = "Update DeptEmployee set department = :newDepartment where employeeNumber = :employeeNo"), ... })

Notez que la requête HQL peut être une opération de style DML. Il n'est donc pas nécessaire qu'il s'agisse uniquement d' une instruction select . Par exemple, nous pouvons avoir une requête de mise à jour comme dans DeptEmployee_UpdateEmployeeDesignation ci-dessus.

3.1. Configuration des fonctionnalités de requête

Nous pouvons définir diverses fonctionnalités de requête avec l' annotation @NamedQuery . Regardons un exemple:

@org.hibernate.annotations.NamedQuery( name = "DeptEmployee_FindAllByDepartment", query = "from DeptEmployee where department = :department", timeout = 1, fetchSize = 10 )

Ici, nous avons configuré l'intervalle de délai et la taille de récupération. En dehors de ces deux, nous pouvons également définir des fonctionnalités telles que:

  • peut être mis en cache - si la requête (les résultats) peut ou non être mise en cache
  • cacheMode - le mode de cache utilisé pour cette requête; il peut s'agir de GET, IGNORE, NORMAL, PUT ou REFRESH
  • cacheRegion - si les résultats de la requête peuvent être mis en cache, nommez la région de cache de requête à utiliser
  • comment - un commentaire ajouté à la requête SQL générée; ciblé pour les administrateurs de base de données
  • flushMode - le mode de vidage pour cette requête, l'un parmi ALWAYS, AUTO, COMMIT, MANUAL ou PERSISTENCE_CONTEXT

3.2. Utilisation de la requête nommée

Maintenant que nous avons défini la requête nommée, utilisons-la pour récupérer un employé:

Query query = session.createNamedQuery("DeptEmployee_FindByEmployeeNumber", DeptEmployee.class); query.setParameter("employeeNo", "001"); DeptEmployee result = query.getSingleResult(); 

Ici, nous avons utilisé la méthode createNamedQuery . Il prend le nom de la requête et renvoie un objet org.hibernate.query.Query .

4. Requête native nommée

En plus des requêtes HQL, nous pouvons également définir le SQL natif en tant que requête nommée. Pour ce faire, nous pouvons utiliser l' annotation @NamedNativeQuery . Bien qu'il soit similaire à @NamedQuery , il nécessite un peu plus de configuration.

Explorons cette annotation à l'aide d'un exemple:

@org.hibernate.annotations.NamedNativeQueries( @org.hibernate.annotations.NamedNativeQuery(name = "DeptEmployee_GetEmployeeByName", query = "select * from deptemployee emp where name=:name", resultClass = DeptEmployee.class) )

Comme il s'agit d'une requête native, nous devrons indiquer à Hibernate à quelle classe d'entité mapper les résultats. Par conséquent, nous avons utilisé la propriété resultClass pour ce faire.

Une autre façon de mapper les résultats consiste à utiliser la propriété resultSetMapping . Ici, nous pouvons spécifier le nom d'un SQLResultSetMapping prédéfini .

Notez que nous ne pouvons utiliser qu'un seul résultatClass et resultSetMapping .

4.1. Utilisation de la requête native nommée

Pour utiliser la requête native nommée, nous pouvons utiliser Session.createNamedQuery () :

Query query = session.createNamedQuery("DeptEmployee_FindByEmployeeName", DeptEmployee.class); query.setParameter("name", "John Wayne"); DeptEmployee result = query.getSingleResult();

Ou le Session.getNamedNativeQuery () :

NativeQuery query = session.getNamedNativeQuery("DeptEmployee_FindByEmployeeName"); query.setParameter("name", "John Wayne"); DeptEmployee result = (DeptEmployee) query.getSingleResult();

La seule différence entre ces deux approches est le type de retour. La deuxième approche renvoie un NativeQuery, qui est une sous-classe de Query .

5. Procédures et fonctions stockées

Nous pouvons également utiliser l' annotation @NamedNativeQuery pour définir des appels aux procédures et fonctions stockées:

@org.hibernate.annotations.NamedNativeQuery( name = "DeptEmployee_UpdateEmployeeDesignation", query = "call UPDATE_EMPLOYEE_DESIGNATION(:employeeNumber, :newDesignation)", resultClass = DeptEmployee.class)

Notez que bien qu'il s'agisse d'une requête de mise à jour, nous avons utilisé la propriété resultClass . En effet, Hibernate ne prend pas en charge les requêtes scalaires natives pures. Et le moyen de contourner le problème consiste à définir un resultClass ou un resultSetMapping.

6. Conclusion

Dans cet article, nous avons vu comment définir et utiliser des requêtes HQL nommées et natives.

Le code source est disponible à l'adresse over sur GitHub.