Requête nommée Hibernate

Requête nommée Hibernate

1. Vue d'ensemble

Le fait que HQL et SQL soient dispersés sur des objets d'accès aux données présente l'inconvénient majeur de rendre le code illisible. Par conséquent, il pourrait être judicieux de regrouper tous les codes HQL et SQL en un seul endroit et d’utiliser uniquement leur référence dans le code d’accès aux données. Heureusement, Hibernate nous permet de le faire avec des requêtes nommées.

Une requête nommée est une requête statiquement définie 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 permet à l'application de tomber rapidement en panne en cas d'erreur.

Dans cet article, nous allons voir 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'annotationorg.hibernate.annotations.NamedQuery. Il étend les javax.persistence.NamedQuery avec les fonctionnalités Hibernate.

Nous allons le définir comme une annotation de la classeDeptEmployee:

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

It’s important to note that every @NamedQuery annotation is attached to exactly one entity class or mapped superclass. But,since the scope of named queries is the entire persistence unit, we should select the query name carefully to avoid a 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 que ce soit une instructionselect uniquement. Par exemple, nous pouvons avoir une requête de mise à jour comme dansDeptEmployee_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é le délai d'expiration et la taille de la récupération. Outre ces deux éléments, nous pouvons également définir des fonctionnalités telles que:

  • cacheable - si la requête (résultats) peut être mise en cache ou non

  • cacheMode - le mode de cache utilisé pour cette requête; cela peut être l'un desGET, IGNORE, NORMAL, PUT, ouREFRESH

  • cacheRegion - si les résultats de la requête peuvent être mis en cache, nommez la région du 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 desALWAYS, AUTO, COMMIT, MANUAL, ouPERSISTENCE_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éthodecreateNamedQuery. Il prend le nom de la requête et renvoie un objetorg.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 aux@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 spropertyresultClass pour ce faire.

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

Notez que nous ne pouvons utiliser qu'un seul desresultClass etresultSetMapping.

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

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

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

Ou lesSession.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 seconde approche renvoie unNativeQuery, which qui est une sous-classe deQuery.

5. Procédures et fonctions stockées

Nous pouvons également utiliser l'annotation@NamedNativeQuery pour définir les 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 spropertyresultClass . En effet, Hibernate ne prend pas en charge les requêtes scalaires natives pures. Et la façon de contourner le problème est de définir unresultClass  ou unresultSetMapping.

6. Conclusion

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

Le code source est disponibleover on GitHub.