Hibernate Named Query

1. Panoramica

Uno dei principali svantaggi di avere HQL e SQL sparsi tra gli oggetti di accesso ai dati è che rende il codice illeggibile. Quindi, potrebbe avere senso raggruppare tutti gli HQL e SQL in un unico posto e utilizzare solo il loro riferimento nel codice di accesso ai dati effettivo. Fortunatamente, Hibernate ci consente di farlo con query con nome.

Una query denominata è una query definita staticamente con una stringa di query non modificabile predefinita. Vengono convalidati quando viene creato il session factory, rendendo così l'applicazione inefficace in caso di errore.

In questo articolo, vedremo come definire e utilizzare le query denominate Hibernate utilizzando le annotazioni @NamedQuery e @NamedNativeQuery .

2. L'Entità

Diamo prima un'occhiata all'entità che useremo in questo articolo:

@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 }

Nel nostro esempio, recupereremo un dipendente in base al suo numero di dipendente.

3. Query denominata

Per definirlo come una query con nome, utilizzeremo l' annotazione org.hibernate.annotations.NamedQuery . Estende javax .persistence.NamedQuery con le funzionalità di Hibernate.

Lo definiremo come un'annotazione della classe DeptEmployee :

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

È importante notare che ogni annotazione @NamedQuery è allegata esattamente a una classe entità o superclasse mappata. Tuttavia, poiché l'ambito delle query denominate è l'intera unità di persistenza, è necessario selezionare attentamente il nome della query per evitare una collisione. E abbiamo ottenuto questo risultato utilizzando il nome dell'entità come prefisso.

Se abbiamo più di una query con nome per un'entità, useremo l' annotazione @NamedQueries per raggrupparli:

@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"), ... })

Notare che la query HQL può essere un'operazione in stile DML. Quindi, non è necessario che sia solo un'istruzione select . Ad esempio, possiamo avere una query di aggiornamento come in DeptEmployee_UpdateEmployeeDesignation sopra.

3.1. Configurazione delle funzionalità di query

Possiamo impostare varie funzionalità di query con l' annotazione @NamedQuery . Diamo un'occhiata a un esempio:

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

Qui, abbiamo configurato l'intervallo di timeout e la dimensione del recupero. Oltre a questi due, possiamo anche impostare funzionalità come:

  • cacheable : indica se la query (risultati) è memorizzabile o meno
  • cacheMode - la modalità cache utilizzata per questa query; può essere una delle opzioni GET, IGNORE, NORMAL, PUT o REFRESH
  • cacheRegion : se i risultati della query sono memorizzabili nella cache, assegna un nome alla regione della cache della query da utilizzare
  • commento : un commento aggiunto alla query SQL generata; destinato agli amministratori di database
  • flushMode : la modalità flush per questa query, una tra SEMPRE, AUTO, COMMIT, MANUAL o PERSISTENCE_CONTEXT

3.2. Utilizzo della query con nome

Ora che abbiamo definito la query denominata, usiamola per recuperare un dipendente:

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

Qui abbiamo utilizzato il metodo createNamedQuery . Prende il nome della query e restituisce un oggetto org.hibernate.query.Query .

4. Query nativa denominata

Oltre alle query HQL, possiamo anche definire SQL nativo come query con nome. Per fare ciò, possiamo usare l' annotazione @NamedNativeQuery . Sebbene sia simile a @NamedQuery , richiede un po 'più di configurazione.

Esploriamo questa annotazione utilizzando un esempio:

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

Poiché questa è una query nativa, dovremo dire a Hibernate a quale classe di entità mappare i risultati. Di conseguenza, abbiamo utilizzato la proprietà resultClass per farlo.

Un altro modo per mappare i risultati consiste nell'usare la proprietà resultSetMapping . Qui possiamo specificare il nome di un SQLResultSetMapping predefinito .

Nota che possiamo usare solo uno tra resultClass e resultSetMapping .

4.1. Utilizzo della query nativa denominata

Per utilizzare la query nativa denominata, possiamo utilizzare Session.createNamedQuery () :

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

Oppure Session.getNamedNativeQuery () :

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

L'unica differenza tra questi due approcci è il tipo restituito. Il secondo approccio restituisce NativeQuery, che è una sottoclasse di Query .

5. Stored procedure e funzioni

Possiamo usare l' annotazione @NamedNativeQuery anche per definire chiamate a stored procedure e funzioni:

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

Si noti che sebbene questa sia una query di aggiornamento, abbiamo utilizzato la proprietà resultClass . Questo perché Hibernate non supporta le query scalari native pure. E il modo per aggirare il problema è impostare un resultClass o un resultSetMapping.

6. Conclusione

In questo articolo, abbiamo visto come definire e utilizzare HQL con nome e query native.

Il codice sorgente è disponibile su GitHub.