JPA / dvale fremskrivninger

1. Oversigt

I denne vejledning lærer vi hvordan man projicerer enhedsegenskaber ved hjælp af JPA og Hibernate.

2. Enheden

Lad os først se på den enhed, vi bruger i denne artikel:

@Entity offentlig klasse produkt {@Id privat langt id; privat strengnavn; privat streng beskrivelse; privat streng kategori; privat BigDecimal enhedPris; // settere og getters}

Dette er en simpel enhedsklasse, der repræsenterer et produkt med forskellige egenskaber.

3. JPA-fremskrivninger

Selvom JPA-specifikationen ikke nævner fremskrivninger eksplicit, er der mange tilfælde, hvor vi finder dem i konceptet.

Typisk har en JPQL-forespørgsel en kandidat-enhedsklasse. Forespørgslen opretter ved udførelse objekter fra kandidatklassen - der udfylder alle deres egenskaber ved hjælp af de hentede data.

Men det er muligt at hente et undersæt af enhedens egenskaber, eller det vil sige en projektion af kolonnedata.

Bortset fra kolonnedata, Vi kan også projicere resultaterne af grupperingsfunktioner.

3.1. Fremskrivninger med en søjle

Lad os antage, at vi vil angive navnene på alle produkter. I JPQL kan vi gøre dette ved kun at medtage navn i Vælg klausul:

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

Eller vi kan gøre det samme med CriteriaBuilder:

CriteriaBuilder builder = entityManager.getCriteriaBuilder (); CriteriaQuery-forespørgsel = builder.createQuery (String.class); Rodprodukt = forespørgsel.fra (Product.class); query.select (product.get ("navn")); Liste resultatListe = entityManager.createQuery (forespørgsel) .getResultList ();

Fordi vi projicerer en enkelt kolonne, der tilfældigvis er af typen Snor, vi forventer at få en liste over Snors i resultatet. Derfor har vi specificeret kandidatklassen som Snor i createQuery () metode.

Da vi ønsker at projicere på en enkelt ejendom, vi har brugt Query.select () metode. Hvad der går her er, hvilken ejendom vi ønsker, så i vores tilfælde bruger vi navn ejendom fra vores Produkt enhed.

Lad os nu se på et eksempel på output, der er genereret af ovenstående to forespørgsler:

Produktnavn 1 Produktnavn 2 Produktnavn 3 Produktnavn 4

Noter det hvis vi havde brugt id ejendom i fremskrivningen i stedet for navn, ville forespørgslen have returneret en liste over Lang genstande.

3.2. Fremskrivninger med flere søjler

For at projicere på flere kolonner ved hjælp af JPQL behøver vi kun tilføje alle de krævede kolonner til Vælg klausul:

Query query = session.createQuery ("vælg id, navn, enhedspris fra produkt"); Liste resultList = query.getResultList ();

Men når du bruger en CriteriaBuilder, vi bliver nødt til at gøre tingene lidt anderledes:

CriteriaBuilder builder = session.getCriteriaBuilder (); CriteriaQuery-forespørgsel = builder.createQuery (objekt []. Klasse); Rodprodukt = forespørgsel.fra (Product.class); query.multiselect (product.get ("id"), product.get ("name"), product.get ("unitPrice")); Liste resultatListe = entityManager.createQuery (forespørgsel) .getResultList ();

Her, vi har brugt metoden multivælg () i stedet for Vælg(). Ved hjælp af denne metode kan vi angive flere emner, der skal vælges.

En anden væsentlig ændring er brugen af Objekt[]. Når vi vælger flere emner, returnerer forespørgslen et objektarray med værdi for hvert projekt, der projiceres. Dette er også tilfældet med JPQL.

Lad os se, hvordan dataene ser ud, når vi udskriver 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 returnerede data lidt besværlige at behandle. Men heldigvis vi kan få JPA til at udfylde disse data i en brugerdefineret klasse.

Vi kan også bruge CriteriaBuilder.tuple () eller CriteriaBuilder.construct () for at få resultaterne som en liste over Tuple objekter eller objekter af en brugerdefineret klasse.

3.3. Projicering af samlede funktioner

Bortset fra kolonnedata vil vi måske nogle gange gruppere dataene og bruge samlede funktioner, som f.eks tælle og gennemsnit.

Lad os sige, at vi vil finde antallet af produkter i hver kategori. Vi kan gøre dette ved hjælp af tælle() samlet funktion i JPQL:

Forespørgselsforespørgsel = entityManager.createQuery ("vælg p.kategori, antal (p) fra produkt p-gruppe efter p.kategori");

Eller vi kan bruge CriteriaBuilder:

CriteriaBuilder builder = entityManager.getCriteriaBuilder (); CriteriaQuery-forespørgsel = builder.createQuery (objekt []. Klasse); Rodprodukt = forespørgsel.fra (Product.class); query.multiselect (product.get ("category"), builder.count (product)); query.groupBy (product.get ("kategori"));

Her har vi brugt CriteriaBuilder'S tælle() metode.

Brug af et af ovenstående producerer en liste over objektarrays:

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

Undtagen tælle(), CriteriaBuilder giver forskellige andre samlede funktioner:

  • gns - Beregner gennemsnitsværdien for en kolonne i en gruppe
  • maks - Beregner den maksimale værdi for en kolonne i en gruppe
  • min - Beregner minimumsværdien for en kolonne i en gruppe
  • mindst - Finder de mindste af kolonneværdierne (for eksempel alfabetisk eller efter dato)
  • sum - Beregner summen af ​​kolonneværdierne i en gruppe

4. Dvale fremskrivninger

I modsætning til JPA giver Hibernate org.hibernate.criterion.Projection til projicering med en Kriterier forespørgsel. Det giver også en klasse kaldet org.hibernate.criterion.Projections, en fabrik til Fremskrivning tilfælde.

4.1. Fremskrivninger med en søjle

Lad os først se, hvordan vi kan projicere en enkelt kolonne. Vi bruger eksemplet, vi så tidligere:

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

Vi har brugt Criteria.setProjection () metode til at specificere den egenskab, vi ønsker i forespørgselsresultatet. Projections.property () gør det samme arbejde for os som Root.get () gjorde når du angiver den kolonne, du skal vælge.

4.2. Fremskrivninger med flere søjler

For at projicere flere kolonner skal vi først oprette en Projektionsliste. Projektionsliste er en særlig slags Fremskrivning der omslutter andre fremskrivninger for at tillade valg af flere værdier.

Vi kan oprette en Projektionslistebruger Projections.projectionList () metode, som at vise Produkt'S id og navn:

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

4.3. Projicering af samlede funktioner

Ligesom CriteriaBuilder, det Fremskrivninger klasse giver også metoder til samlede funktioner.

Lad os se, hvordan vi kan implementere det tælleeksempel, vi så tidligere:

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

Det er vigtigt at bemærke det vi specificerede ikke GROUP BY direkte i Kriterier objekt. Ringer gruppeEjendom udløser dette for os.

Bortset fra rækkeCount () fungere, Fremskrivninger giver også de samlede funktioner, vi så tidligere.

4.4. Brug af et alias til en projektion

Et interessant træk ved Hibernate Criteria API er brugen af ​​et alias til en projektion.

Dette er især nyttigt, når du bruger en samlet funktion, da vi derefter kan henvise til aliaset i Kriterium og Bestille tilfælde:

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. Konklusion

I denne artikel så vi, hvordan vi projicerer enhedsejendomme ved hjælp af JPA og Hibernate.

Det er vigtigt at bemærke det Hibernate har udfaset sin Criteria API fra version 5.2 og fremefter til fordel for JPA CriteriaQuery API. Men dette er kun fordi Hibernate-teamet ikke har tid til at holde to forskellige API'er, der stort set gør det samme synkroniseret.

Og selvfølgelig kan koden, der bruges i denne artikel, findes på GitHub.


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