JPA / Hibernate Projections

1. Oversikt

I denne opplæringen lærer vi hvordan du projiserer enhetsegenskaper ved hjelp av JPA og Hibernate.

2. Enheten

La oss først se på enheten vi skal bruke gjennom denne artikkelen:

@Entity offentlig klasse Produkt {@Id privat lang id; privat strengnavn; privat strengbeskrivelse; privat streng kategori; privat BigDecimal unitPrice; // setters og getters}

Dette er en enkel enhetsklasse som representerer et produkt med forskjellige egenskaper.

3. JPA-projeksjoner

Selv om JPA-spesifikasjonen ikke nevner anslag eksplisitt, er det mange tilfeller der vi finner dem i konseptet.

Vanligvis har et JPQL-søk en kandidat-enhetsklasse. Spørringen, ved utførelse, oppretter objekter fra kandidatklassen - fylle ut alle egenskapene deres ved hjelp av dataene som er hentet.

Men det er mulig å hente et delsett av egenskapene til enheten, eller det vil si a projeksjon av kolonnedata.

Bortsett fra kolonnedata, vi kan også projisere resultatene av grupperingsfunksjoner.

3.1. Framskrivinger med en kolonne

La oss anta at vi vil liste opp navnene på alle produktene. I JPQL kan vi gjøre dette ved å bare inkludere Navn i å velge klausul:

Query query = entityManager.createQuery ("velg navn fra produkt"); Liste resultList = query.getResultList ();

Eller, vi kan gjøre det samme med CriteriaBuilder:

CriteriaBuilder builder = entityManager.getCriteriaBuilder (); CriteriaQuery-spørring = builder.createQuery (String.class); Rotprodukt = query.from (Product.class); query.select (product.get ("navn")); Liste resultList = entityManager.createQuery (spørring) .getResultList ();

Fordi vi projiserer en enkelt kolonne som tilfeldigvis er av type String, forventer vi å få en liste over Strings i resultatet. Derfor har vi spesifisert kandidatklassen som String i createQuery () metode.

Siden vi ønsker å projisere på en enkelt eiendom, vi har brukt Query.select () metode. Det som går her er hvilken eiendom vi vil ha, så i vårt tilfelle vil vi bruke Navn eiendom fra vår Produkt enhet.

La oss nå se på en prøveutgang generert av de ovennevnte to spørsmålene:

Produktnavn 1 Produktnavn 2 Produktnavn 3 Produktnavn 4

Noter det hvis vi hadde brukt id eiendom i projeksjonen i stedet for Navn, ville spørringen ha returnert en liste over Lang gjenstander.

3.2. Projektering med flere kolonner

For å projisere på flere kolonner ved hjelp av JPQL, trenger vi bare å legge til alle nødvendige kolonner i å velge klausul:

Query query = session.createQuery ("velg id, navn, enhetspris fra produkt"); Liste resultList = query.getResultList ();

Men når du bruker en CriteriaBuilder, vi må gjøre ting litt annerledes:

CriteriaBuilder builder = session.getCriteriaBuilder (); CriteriaQuery query = builder.createQuery (Object []. Class); Rotprodukt = spørring.fra (Product.class); query.multiselect (product.get ("id"), product.get ("name"), product.get ("unitPrice")); Liste resultatListe = entityManager.createQuery (spørring) .getResultList ();

Her, vi har brukt metoden Flervalg() i stedet for å velge(). Ved hjelp av denne metoden kan vi spesifisere flere elementer som skal velges.

En annen betydelig endring er bruken av Gjenstand[]. Når vi velger flere elementer, returnerer spørringen en objektmatrise med verdi for hvert prosjekt som er projisert. Dette er også tilfelle med JPQL.

La oss se hvordan dataene ser ut når vi skriver ut dem:

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

Som vi kan se, er de returnerte dataene litt tungvint å behandle. Men heldigvis vi kan få JPA til å fylle ut disse dataene i en tilpasset klasse.

Vi kan også bruke CriteriaBuilder.tuple () eller CriteriaBuilder.construct () for å få resultatene som en liste over Tuple objekter eller objekter av en tilpasset klasse.

3.3. Projiserende samlede funksjoner

Bortsett fra kolonnedata, kan det være lurt å gruppere dataene og bruke samlede funksjoner, for eksempel telle og gjennomsnitt.

La oss si at vi vil finne antall produkter i hver kategori. Vi kan gjøre dette ved hjelp av telle() samlet funksjon i JPQL:

Query query = entityManager.createQuery ("velg p.category, count (p) fra Product p group by p.category");

Eller vi kan bruke CriteriaBuilder:

CriteriaBuilder builder = entityManager.getCriteriaBuilder (); CriteriaQuery query = builder.createQuery (Object []. Class); Rotprodukt = spørring.fra (Product.class); query.multiselect (product.get ("category"), builder.count (product)); query.groupBy (product.get ("category"));

Her har vi brukt CriteriaBuilder‘S telle() metode.

Å bruke en av de ovennevnte vil produsere en liste over objektmatriser:

[kategori1, 2] [kategori2, 1] [kategori3, 1]

Bortsett fra telle(), CriteriaBuilder gir forskjellige andre samlede funksjoner:

  • gj.sn. - Beregner gjennomsnittsverdien for en kolonne i en gruppe
  • maks - Beregner maksimumsverdien for en kolonne i en gruppe
  • min - Beregner minimumsverdien for en kolonne i en gruppe
  • minst - Finner minst av kolonneverdiene (for eksempel alfabetisk eller etter dato)
  • sum - Beregner summen av kolonneverdiene i en gruppe

4. Dvalemodusprojeksjoner

I motsetning til JPA gir Hibernate org.hibernate.criterion.Projection for projisering med en Kriterier spørsmål. Det gir også en klasse som heter org.hibernate.criterion.Projections, en fabrikk for Projeksjon tilfeller.

4.1. Framskrivinger med en kolonne

La oss først se hvordan vi kan projisere en enkelt kolonne. Vi bruker eksemplet vi så tidligere:

Kriteriekriterier = session.createCriteria (Product.class); kriterier = criteria.setProjection (Projections.property ("navn")); 

Vi har brukt Criteria.setProjection () metode for å spesifisere egenskapen vi ønsker i søkeresultatet. Projections.property () gjør det samme arbeidet for oss som Root.get () gjorde når kolonnen skal velges.

4.2. Projektering med flere kolonner

For å projisere flere kolonner, må vi først opprette en Projeksjonsliste. Projeksjonsliste er en spesiell type Projeksjon som omgir andre projeksjoner for å tillate valg av flere verdier.

Vi kan lage en Projeksjonslistebruker Projections.projectionList () metode, som å vise Produkt‘S id og Navn:

Kriteriekriterier = session.createCriteria (Product.class); kriterier = criteria.setProjection (Projections.projectionList () .add (Projections.id ()) .add (Projections.property ("name")));

4.3. Projiserende samlede funksjoner

Akkurat som CriteriaBuilder, den Anslag klasse gir også metoder for samlede funksjoner.

La oss se hvordan vi kan implementere telleeksemplet vi så tidligere:

Kriteriekriterier = session.createCriteria (Product.class); kriterier = criteria.setProjection (Projections.projectionList () .add (Projections.groupProperty ("category")) .add (Projections.rowCount ()));

Det er viktig å merke seg det vi spesifiserte ikke direkte GROUP BY i Kriterier gjenstand. Ringer gruppeEiendom utløser dette for oss.

Bortsett fra rowCount () funksjon, Anslag gir også de samlede funksjonene vi så tidligere.

4.4. Bruke et alias for en projeksjon

Et interessant trekk ved Hibernate Criteria API er bruken av et alias for en projeksjon.

Dette er spesielt nyttig når du bruker en samlet funksjon, da vi da kan referere til aliaset i Kriterium og Rekkefølge forekomster:

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

5. Konklusjon

I denne artikkelen så vi hvordan du projiserer enhetsegenskaper ved hjelp av JPA og Hibernate.

Det er viktig å merke seg det Hibernate har avviklet Criteria API fra versjon 5.2 og fremover til fordel for JPA CriteriaQuery API. Men dette er bare fordi Hibernate-teamet ikke har tid til å beholde to forskjellige API-er, som stort sett gjør det samme, synkronisert.

Og selvfølgelig kan koden som brukes i denne artikkelen bli funnet på GitHub.


$config[zx-auto] not found$config[zx-overlay] not found