Das JPA-Criteria API ermöglicht eine standardisierte und typsichere Erstellung von objektorientierten Abfragen in Java. Im folgenden soll die Umsetzung einer Join-Abfrage mit Hilfe der Criteria API etwas näher erläutert werden. Ausgangspunkt ist ein Beispiel einer unidirektionalen 1->n Beziehung zwischen zwei Entitätsklassen Person und Adresse. Eine einfache Verknüpfung dieser beiden Entitäten kann auf Basis der JPAQL untypisiert wie folgt ermittelt werden:
select p from Person p join p.adresses
Um die gleiche Join-Query durch das Criteria-API zu formulieren, ist folgende Objekthierarchie zu benutzen. Ein CriteriaQuery-Objekt liefert über die from()-Methode ein From-Interface-Objekt zurück. An diesem kann über die join()-Methode ein entsprechendes Join-Objekt erhalten werden. Als Parameter ist der join()-Methode ein Metamodel-Objekt zu übergeben, welches das Element der abgefragten Klasse beischreibt über die der spätere „Join“ erfolgen soll.
EntityManager em = entityManagerFactory.createEntityManager(); CriteriaBuilder criteriaBuilder = em.getCriteriaBuilder(); CriteriaQuery<Person> criteriaQuery = criteriaBuilder.createQuery(Person.class); Root<Person> person = criteriaQuery.from(Person.class); SetJoin<Person, Address> adressJoin = person.join(Person_.adresses); criteriaQuery.select(person); List<Person> resultList = em.createQuery(criteriaQuery).getResultList();
Das erzeugte Join-Objekt nimmt sowohl das Quell- als auch das Ziel-Objekt des kartesischen Produkts auf. Zum Ausführen der Query ist dann das From-Interface-Objekt als Parameter der select()-Methode des entsprechenden CriteriaQuery-Objektes zu übergeben. Im Anschluss kann diese Query dann durch einen JPA-Entity-Manager ausgeführt werden.
Auf das Join-Objekt kann zugegriffen werden, wenn Attribute des Zielobjektes in einer „select“ oder „where“- Klausel benötigt werden.
EntityManager em = entityManagerFactory.createEntityManager(); CriteriaBuilder criteriaBuilder = em.getCriteriaBuilder(); CriteriaQuery<Person> criteriaQuery = criteriaBuilder.createQuery(Person.class); Root<Person> person = criteriaQuery.from(Person.class); SetJoin<Person, Address> adressJoin = person.join(Person_.adresses); criteriaQuery.where(criteriaBuilder.like(adressJoin.get(Address_.city), "Mannheim")); criteriaQuery.select(person); List<Person> resultList = em.createQuery(criteriaQuery).getResultList();
Die so implementierte Abfrage entspricht in JPAQL:
select p from Person p join p.adresses a where a.city like 'Mannheim'
Die Join Objekte können dabei vom Typ Join, CollectionJoin, SetJoin, ListJoin und MapJoin sein. Der konkrete Typ des jeweils zurückgegebenen Join-Objektes wird vom Typ der Relation bestimmt.
Für einen Join über eine Entität, ein Embeddable oder einen Basis Typen ist das Ergebnisobjekt selbst vom Basistyp Join.
Bei einem Join über eine Collection, die mit java.util.Collecion spezifiziert ist, ist das Ergebnis vom Typ CollectionJoin.
SetJoin ist das Ergebnis eines Join über eine Collection vom Typ java.util.Set. MapJoin hingegen ist das Ergebnis eines Join über eine Collection vom Typ java.util.Map.
Auf einem Join lassen sich im Anschluss mit Hilfe einer where-Klausel Filterungen durchführen wie folgendes Beispiel zeigen soll, das man in JPAQL wie folgt formulieren würde:
select p from Person p join p.adresses a where a.street = 'Weinheimer str.'
Um diese Filterung typsicher durchzuführen, ist das Ausgangsbeispiel wie folgt zu erweitern. Das Join-Objekt wird als Referenz gespeichert und kann so als Parameter zur Erzeugung eines Filter-Objektes in der where()-Methode des CriteriaQuery-Objektes genutzt werden. Der Parameter wird mit Hilfe von Operatoren-Methoden [wie z.B. equal()] des Criteriabuilders gebildet. Dazu kann über die gespeicherte Referenz auf dem Join-Objekt navigiert werden.
EntityManager em = entityManagerFactory.createEntityManager(); CriteriaBuilder criteriaBuilder = em.getCriteriaBuilder(); CriteriaQuery<Person> criteriaQuery = criteriaBuilder.createQuery(Person.class); Root<Person> person = criteriaQuery.from(Person.class); SetJoin<Person, Address> a = person.join(Person_.adresses); criteriaQuery.select(person).where(criteriaBuilder.equal(a.get(Address_.street), "Weinheimer str.")); criteriaQuery.select(person); List<Person> resultList = em.createQuery(criteriaQuery).getResultList();
Man beachte auch hier wieder die Verwendung von Metamodel Objekten der Klasse Person_ um die in der where-Klausel nötige Navigation zu spezifizieren.
Einsortiert unter:Java EE, Java Persistence Tagged: Hibernate Criteria, join, JPA