Tipi di query JPA

1. Panoramica

In questo tutorial, discuteremo i diversi tipi di query JPA. Inoltre, ci concentreremo sul confronto delle differenze tra loro e sull'espansione dei pro e dei contro di ciascuno.

2. Configurazione

In primo luogo, definiamo la classe UserEntity che useremo per tutti gli esempi in questo articolo:

@Table(name = "users") @Entity public class UserEntity { @Id private Long id; private String name; //Standard constructor, getters and setters. }

Esistono tre tipi di base di query JPA:

  • Query , scritto in sintassi Java Persistence Query Language (JPQL)
  • NativeQuery , scritto in semplice sintassi SQL
  • Criteria API Query , costruita a livello di codice tramite metodi diversi

Esploriamoli.

3. Query

Una query è simile nella sintassi a SQL ed è generalmente utilizzata per eseguire operazioni CRUD:

public UserEntity getUserByIdWithPlainQuery(Long id) { Query jpqlQuery = getEntityManager().createQuery("SELECT u FROM UserEntity u WHERE u.id=:id"); jpqlQuery.setParameter("id", id); return (UserEntity) jpqlQuery.getSingleResult(); }

Questa query recupera il record corrispondente dalla tabella degli utenti e lo mappa anche all'oggetto UserEntity .

Esistono due sottotipi di query aggiuntivi :

  • TypedQuery
  • NamedQuery

Vediamoli in azione.

3.1. TypedQuery

Dobbiamo prestare attenzione al ritorno economico nel nostro esempio precedente. JPA non può dedurre quale sarà il tipo di risultato della query e, di conseguenza, dobbiamo eseguire il cast.

Tuttavia, JPA fornisce uno speciale sottotipo Query noto come TypedQuery. Questo è sempre preferito se conosciamo in anticipo il nostro tipo di risultato della query . Inoltre, rende il nostro codice molto più affidabile e facile da testare.

Vediamo un'alternativa a TypedQuery , rispetto al nostro primo esempio:

public UserEntity getUserByIdWithTypedQuery(Long id) { TypedQuery typedQuery = getEntityManager().createQuery("SELECT u FROM UserEntity u WHERE u.id=:id", UserEntity.class); typedQuery.setParameter("id", id); return typedQuery.getSingleResult(); }

In questo modo, otteniamo una digitazione più forte gratuitamente, evitando possibili eccezioni di casting lungo la strada.

3.2. NamedQuery

Sebbene possiamo definire dinamicamente una query su metodi specifici, alla fine possono trasformarsi in una base di codice difficile da mantenere. E se potessimo mantenere le query di utilizzo generale in un luogo centralizzato e di facile lettura?

JPA ci ha anche coperto con un altro sottotipo Query noto come NamedQuery.

Definiamo NamedQuery sulla classe Entity stessa, fornendo un modo centralizzato, rapido e semplice per leggere e trovare le query correlate di Entity .

Tutti i NamedQueries devono avere un nome univoco.

Vediamo come possiamo aggiungere una NamedQuery alla nostra classe UserEntity :

@Table(name = "users") @Entity @NamedQuery(name = "UserEntity.findByUserId", query = "SELECT u FROM UserEntity u WHERE u.id=:userId") public class UserEntity { @Id private Long id; private String name; //Standard constructor, getters and setters. }

L' annotazione @NamedQuery deve essere raggruppata all'interno di un'annotazione @NamedQueries se stiamo usando Java prima della versione 8. Da Java 8 in avanti, possiamo semplicemente ripetere l' annotazione @NamedQuery nella nostra classe Entity .

Usare una NamedQuery è molto semplice:

public UserEntity getUserByIdWithNamedQuery(Long id) { Query namedQuery = getEntityManager().createNamedQuery("UserEntity.findByUserId"); namedQuery.setParameter("userId", id); return (UserEntity) namedQuery.getSingleResult(); }

4. NativeQuery

Una NativeQuery è semplicemente una query SQL. Questi ci consentono di liberare tutta la potenza del nostro database, in quanto possiamo utilizzare funzionalità proprietarie non disponibili nella sintassi limitata a JPQL.

Questo ha un costo. Perdiamo la portabilità del database della nostra applicazione con NativeQuery perché il nostro provider JPA non può più astrarre dettagli specifici dall'implementazione del database o dal fornitore.

Vediamo come utilizzare una NativeQuery che produce gli stessi risultati dei nostri esempi precedenti:

public UserEntity getUserByIdWithNativeQuery(Long id) { Query nativeQuery = getEntityManager().createNativeQuery("SELECT * FROM users WHERE id=:userId", UserEntity.class); nativeQuery.setParameter("userId", id); return (UserEntity) nativeQuery.getSingleResult(); }

Dobbiamo sempre considerare se una NativeQuery è l'unica opzione. La maggior parte delle volte, una buona query JPQL può soddisfare le nostre esigenze e, cosa più importante, mantenere un livello di astrazione dall'attuale implementazione del database.

Usare NativeQuery non significa necessariamente affidarci a uno specifico fornitore di database. Dopo tutto, se le nostre query non utilizzano comandi SQL proprietari e utilizzano solo una sintassi SQL standard, cambiare provider non dovrebbe essere un problema.

5. Criteri API Query

Le query API dei criteri sono query indipendenti dai tipi, costruite in modo programmatico, in qualche modo simili alle query JPQL nella sintassi:

public UserEntity getUserByIdWithCriteriaQuery(Long id) { CriteriaBuilder criteriaBuilder = getEntityManager().getCriteriaBuilder(); CriteriaQuery criteriaQuery = criteriaBuilder.createQuery(UserEntity.class); Root userRoot = criteriaQuery.from(UserEntity.class); UserEntity queryResult = getEntityManager().createQuery(criteriaQuery.select(userRoot) .where(criteriaBuilder.equal(userRoot.get("id"), id))) .getSingleResult(); return queryResult; }

Può essere scoraggiante utilizzare le query API Criteria in prima persona, ma possono essere un'ottima scelta quando è necessario aggiungere elementi di query dinamici o quando sono accoppiati con il metamodello JPA .

6. Conclusione

In questo rapido articolo, abbiamo appreso cosa sono le query JPA, insieme al loro utilizzo.

Le query JPA sono un ottimo modo per astrarre la nostra logica aziendale dal nostro livello di accesso ai dati poiché possiamo fare affidamento sulla sintassi JPQL e lasciare che il nostro provider JPA preferito gestisca la traduzione delle query .

Tutto il codice presentato in questo articolo è disponibile su GitHub.