JPA / slaapstand-projecties

1. Overzicht

In deze tutorial leren we hoe entiteitseigenschappen te projecteren met JPA en Hibernate.

2. De entiteit

Laten we eerst eens kijken naar de entiteit die we in dit artikel zullen gebruiken:

@Entity public class Product {@Id privé lange id; private String naam; private String beschrijving; privé String-categorie; privé BigDecimal unitPrice; // setters en getters}

Dit is een eenvoudige entiteitsklasse die een product vertegenwoordigt met verschillende eigenschappen.

3. JPA-projecties

Hoewel de JPA-specificatie projecties niet expliciet vermeldt, zijn er veel gevallen waarin we ze in concept aantreffen.

Meestal heeft een JPQL-query een kandidaat-entiteitsklasse. De query maakt bij uitvoering objecten van de kandidaatklasse, waarbij al hun eigenschappen worden gevuld met behulp van de opgehaalde gegevens.

Maar het is mogelijk een subset van de eigenschappen van de entiteit ophalen, of, dat wil zeggen, een projectie van kolomgegevens.

Afgezien van kolomgegevens, we kunnen ook de resultaten van groeperingsfuncties projecteren.

3.1. Projecties met één kolom

Stel dat we de namen van alle producten willen vermelden. In JPQL kunnen we dit doen door alleen de naam in de selecteer clausule:

Query query = entityManager.createQuery ("selecteer naam uit product"); Lijst resultList = query.getResultList ();

Of we kunnen hetzelfde doen met CriteriaBuilder:

CriteriaBuilder-builder = entityManager.getCriteriaBuilder (); CriteriaQuery-query = builder.createQuery (String.class); Root product = query.from (Product.class); query.select (product.get ("naam")); Lijst resultList = entityManager.createQuery (query) .getResultList ();

Omdat we projecteren een enkele kolom die toevallig van het type is Draad, verwachten we een lijst te krijgen van Draads in het resultaat. Daarom hebben we de kandidaat-klasse gespecificeerd als Draad in de createQuery () methode.

Omdat we willen projecteren op een enkele eigenschap, we hebben de Query.select () methode. Wat hier gaat, is welke eigenschap we willen, dus in ons geval zouden we de naam eigendom van onze Product entiteit.

Laten we nu eens kijken naar een voorbeelduitvoer gegenereerd door de bovenstaande twee query's:

Productnaam 1 Productnaam 2 Productnaam 3 Productnaam 4

Let daar op als we de ID kaart eigenschap in de projectie in plaats van naam, zou de query een lijst met Lang voorwerpen.

3.2. Projecties met meerdere kolommen

Om met JPQL op meerdere kolommen te projecteren, hoeven we alleen alle vereiste kolommen toe te voegen aan het selecteer clausule:

Queryquery = session.createQuery ("selecteer id, naam, eenheidsprijs van product"); Lijst resultList = query.getResultList ();

Maar bij gebruik van een CriteriaBuilder, we zullen de dingen een beetje anders moeten doen:

CriteriaBuilder-builder = session.getCriteriaBuilder (); CriteriaQuery-query = builder.createQuery (Object []. Klasse); Root product = query.from (Product.class); query.multiselect (product.get ("id"), product.get ("naam"), product.get ("unitPrice")); Lijst resultList = entityManager.createQuery (query) .getResultList ();

Hier, we hebben de methode gebruikt multi-Select() in plaats van selecteer (). Met deze methode kunnen we meerdere items specificeren die moeten worden geselecteerd.

Een andere belangrijke verandering is het gebruik van Voorwerp[]. Als we meerdere items selecteren, retourneert de query een objectmatrix met waarde voor elk geprojecteerd item. Dit is ook het geval met JPQL.

Laten we eens kijken hoe de gegevens eruit zien als we ze afdrukken:

[1, Productnaam 1, 1.40] [2, Productnaam 2, 4.30] [3, Productnaam 3, 14.00] [4, Productnaam 4, 3.90]

Zoals we kunnen zien, zijn de geretourneerde gegevens een beetje omslachtig om te verwerken. Maar gelukkig, we kunnen JPA ertoe brengen om deze gegevens in een aangepaste klasse te vullen.

We kunnen ook gebruiken CriteriaBuilder.tuple () of CriteriaBuilder.construct () om de resultaten te krijgen als een lijst met Tuple objecten of objecten van een aangepaste klasse.

3.3. Geaggregeerde functies projecteren

Afgezien van kolomgegevens, willen we soms de gegevens groeperen en geaggregeerde functies gebruiken, zoals tellen en gemiddelde.

Stel dat we het aantal producten in elke categorie willen vinden. We kunnen dit doen met behulp van de tellen () geaggregeerde functie in JPQL:

Queryquery = entityManager.createQuery ("selecteer p.category, tel (p) uit Product p group by p.category");

Of we kunnen gebruiken CriteriaBuilder:

CriteriaBuilder-builder = entityManager.getCriteriaBuilder (); CriteriaQuery-query = builder.createQuery (Object []. Klasse); Root product = query.from (Product.class); query.multiselect (product.get ("categorie"), builder.count (product)); query.groupBy (product.get ("categorie"));

Hier hebben we gebruikt CriteriaBuilder‘S tellen () methode.

Als u een van de bovenstaande methoden gebruikt, wordt een lijst met objectmatrices geproduceerd:

[categorie1, 2] [categorie2, 1] [categorie3, 1]

Losstaand van tellen (), CriteriaBuilder biedt verschillende andere geaggregeerde functies:

  • gem - Berekent de gemiddelde waarde voor een kolom in een groep
  • max. hoogte - Berekent de maximale waarde voor een kolom in een groep
  • min - Berekent de minimumwaarde voor een kolom in een groep
  • minst - Vindt de minste kolomwaarden (bijvoorbeeld alfabetisch of op datum)
  • som - Berekent de som van de kolomwaarden in een groep

4. Slaapstandprojecties

In tegenstelling tot JPA biedt Hibernate org.hibernate.criterion.Projection voor projecteren met een Criteria vraag. Het biedt ook een klasse met de naam org.hibernate.criterion.Projections, een fabriek voor Projectie gevallen.

4.1. Projecties met één kolom

Laten we eerst eens kijken hoe we een enkele kolom kunnen projecteren. We gebruiken het voorbeeld dat we eerder zagen:

Criteria criteria = session.createCriteria (Product.class); criteria = criteria.setProjection (Projections.property ("naam")); 

We hebben de Criteria.setProjection () methode om de eigenschap op te geven die we willen in het queryresultaat. Projections.property () doet bij ons hetzelfde werk als Root.get () deed bij het aangeven van de te selecteren kolom.

4.2. Projecties met meerdere kolommen

Om meerdere kolommen te projecteren, moeten we eerst een ProjectionList. ProjectionList is een speciaal soort Projectie die andere projecties omhult om het selecteren van meerdere waarden mogelijk te maken.

We kunnen een ProjectionListde ... gebruiken Projections.projectionList () methode, zoals het tonen van de Product‘S ID kaart en naam:

Criteria criteria = session.createCriteria (Product.class); criteria = criteria.setProjection (Projections.projectionList () .add (Projections.id ()) .add (Projections.property ("naam")));

4.3. Geaggregeerde functies projecteren

Net als CriteriaBuilder, de Projecties class biedt ook methoden voor geaggregeerde functies.

Laten we eens kijken hoe we het telvoorbeeld kunnen implementeren dat we eerder zagen:

Criteria criteria = session.createCriteria (Product.class); criteria = criteria.setProjection (Projections.projectionList () .add (Projections.groupProperty ("categorie")) .add (Projections.rowCount ()));

Het is belangrijk om dat op te merken we hebben de GROUP BY niet direct gespecificeerd in het Criteria voorwerp. Roeping groupProperty triggert dit voor ons.

Los van de aantal rijen() functie, Projecties biedt ook de geaggregeerde functies die we eerder zagen.

4.4. Een alias gebruiken voor een projectie

Een interessant kenmerk van de Hibernate Criteria API is het gebruik van een alias voor een projectie.

Dit is vooral handig bij het gebruik van een geaggregeerde functie, omdat we dan kunnen verwijzen naar de alias in het Criterium en Bestellen gevallen:

Criteria criteria = session.createCriteria (Product.class); criteria = criteria.setProjection (Projections.projectionList () .add (Projections.groupProperty ("categorie")) .add (Projections.alias (Projections.rowCount (), "count"))); criteria.addOrder (Order.asc ("count"));

5. Conclusie

In dit artikel hebben we gezien hoe entiteitseigenschappen kunnen worden geprojecteerd met JPA en Hibernate.

Het is belangrijk om in acht te nemen dat Hibernate heeft zijn Criteria API vanaf versie 5.2 verouderd ten gunste van de JPA CriteriaQuery API. Maar dit is alleen omdat het Hibernate-team niet de tijd heeft om twee verschillende API's, die vrijwel hetzelfde doen, gesynchroniseerd te houden.

En natuurlijk is de code die in dit artikel wordt gebruikt, te vinden op GitHub.