En guide til SqlResultSetMapping

1. Introduktion

I denne vejledning ser vi på SqlResultSetMapping, ud af Java Persistence API (JPA).

Kernefunktionaliteten her involverer kortlægning af resultatsæt fra SQL-database-sætninger til Java-objekter.

2. Opsætning

Før vi ser på brugen, lad os lave nogle opsætninger.

2.1. Maven afhængighed

Vores krævede Maven-afhængigheder er dvale- og H2-database. Dvaletilstand giver os implementeringen af ​​JPA-specifikationen. Vi bruger H2-database til en in-memory-database.

2.2. Database

Derefter opretter vi to tabeller som vist her:

OPRET TABEL MEDARBEJDER (id BIGINT, navn VARCHAR (10));

Det MEDARBEJDER bord gemmer et resultat Enhed objekt. SCHEDULE_DAYS indeholder poster, der er knyttet til MEDARBEJDER tabel ved kolonnen Medarbejder-ID:

CREATE TABLE SCHEDULE_DAYS (id IDENTITY, employeeId BIGINT, dayOfWeek VARCHAR (10));

Et script til oprettelse af data kan findes i koden til denne vejledning.

2.3. Enhedsobjekter

Vores Enhed genstande skal se ens ud:

@Entity offentlig klassemedarbejder {@Id privat Lang id; privat strengnavn; }

Enhed objekter kan navngives forskelligt fra databasetabeller. Vi kan kommentere klassen med @Bord for eksplicit at kortlægge dem:

@Entity @Table (name = "SCHEDULE_DAYS") offentlig klasse Planlagt dag {@Id @GeneratedValue privat Lang id; privat Lang medarbejder-ID; privat strengdagOfWeek; }

3. Scalar Mapping

Nu hvor vi har data, kan vi starte kortlægning af forespørgselsresultater.

3.1. KolonneResultat

Mens SqlResultSetMapping og Forespørgsel annoteringer arbejder på Datalager også, bruger vi kommentarerne på en Enhed klasse i dette eksempel.

Hver SqlResultSetMapping annotering kræver kun en ejendom, navn. Uden en af ​​medlemstyperne kortes der imidlertid intet. Medlemstyperne er ColumnResult, ConstructorResultog EntityResult.

I dette tilfælde, ColumnResult kortlægger en hvilken som helst kolonne til en skalær resultattype:

@SqlResultSetMapping (navn = "FridayEmployeeResult", kolonner = {@ ColumnResult (navn = "medarbejder-id")})

Det ColumnResult ejendom navn identificerer kolonnen i vores forespørgsel:

@NamedNativeQuery (navn = "FridayMedarbejdere", forespørgsel = "VÆLG medarbejderId FRA skema_dage HVOR dayOfWeek = 'FRIDAY'", resultSetMapping = "FridayEmployeeResult") 

Noter det værdien af resultSetMapping i vores NamedNativeQuery kommentar er vigtigt, fordi det matcher navn ejendom fra vores ResultSetMapping erklæring.

Som et resultat af dette NamedNativeQuery resultatsættet kortlægges som forventet. Ligeledes, Lagret procedure API kræver denne tilknytning.

3.2. ColumnResult Prøve

Vi har brug for nogle dvale-specifikke objekter for at køre vores kode:

@BeforeAll offentlig statisk ugyldig opsætning () {emFactory = Persistence.createEntityManagerFactory ("java-jpa-planlagt dag"); em = emFactory.createEntityManager (); }

Endelig kalder vi den navngivne forespørgsel for at køre vores test:

@Test offentlig ugyldig nårNamedQuery_thenColumnResult () {List medarbejderIds = em.createNamedQuery ("FridayEmployees"). GetResultList (); assertEquals (2, employeeIds.size ()); }

4. Kortlægning af konstruktør

Lad os se på, hvornår vi skal kortlægge et resultatsæt til et helt objekt.

4.1. ConstructorResult

På samme måde som vores ColumnResult eksempel tilføjer vi SqlResultMapping kommentar til vores Enhed klasse, Planlagt dag. For at kortlægge ved hjælp af en konstruktør skal vi dog oprette en:

offentlig planlagt dag (lang id, lang medarbejder-id, hel time In, hel time ud, streng dag af uge) {this.id = id; this.employeeId = medarbejderId; this.dayOfWeek = dayofWeek; }

Kortlægningen specificerer også målklassen og kolonnerne (begge kræves):

@SqlResultSetMapping (name = "ScheduleResult", classes = {@ConstructorResult (targetClass = com.baeldung.sqlresultsetmapping.ScheduledDay.class, columns = {@ColumnResult (name = "id", type = Long.class), @ColumnResult (name) = "medarbejder-id", type = Long.class), @ColumnResult (navn = "dayOfWeek")})})

Rækkefølgen af KolonneResultater er meget vigtigt. Hvis kolonner ikke er i orden, identificeres konstruktøren ikke. I vores eksempel matcher rækkefølgen tabelkolonnerne, så det ville faktisk ikke være nødvendigt.

@NamedNativeQuery (navn = "Schedules", forespørgsel = "VÆLG * FRA skema_dage HVOR medarbejderId = 8", resultSetMapping = "ScheduleResult")

En anden unik forskel for ConstructorResult er, at den resulterende objektinstansiering er "ny" eller "løsrevet". Det kortlagte Enhed vil være i løsrevet tilstand, når der findes en matchende primær nøgle i EntityManager ellers bliver det nyt.

Nogle gange kan vi støde på runtime-fejl på grund af uoverensstemmelse mellem SQL-datatyper og Java-datatyper. Derfor kan vi eksplicit erklære det med type.

4.2. ConstructorResult Prøve

Lad os teste ConstructorResult i en enhedstest:

@Test offentlig ugyldig nårNamedQuery_thenConstructorResult () {List schedDays = Collections.checkedList (em.createNamedQuery ("Schedules", ScheduledDay.class) .getResultList (), ScheduledDay.class); assertEquals (3, schedDays.size ()); assertTrue (schedDays.stream (). allMatch (c -> c.getEmployeeId (). longValue () == 3)); }

5. Enhedskortlægning

Endelig, for en simpel enhedskortlægning med mindre kode, lad os se på EntityResult.

5.1. Enkel enhed

EntityResult kræver, at vi angiver enhedsklassen, Medarbejder. Vi bruger det valgfri felter ejendom for mere kontrol. Kombineret med FieldResult, vi kan kortlægge aliaser og felter, der ikke stemmer overens:

@SqlResultSetMapping (name = "EmployeeResult", entities = {@EntityResult (entityClass = com.baeldung.sqlresultsetmapping.Employee.class, fields = {@FieldResult (name = "id", column = "employeeNumber"), @FieldResult (name = "navn", kolonne = "navn")})})

Nu skal vores forespørgsel omfatte den aliasede kolonne:

@NamedNativeQuery (navn = "Medarbejdere", forespørgsel = "VÆLG id som medarbejderNummer, navn FRA MEDARBEJDER", resultSetMapping = "Medarbejderresultat")

På samme måde som ConstructorResult, EntityResult kræver en konstruktør. En standard fungerer dog her.

5.2. Flere enheder

Kortlægning af flere enheder er ret ligetil, når vi først har kortlagt en enkelt enhed:

@SqlResultSetMapping (name = "EmployeeScheduleResults", entities = {@EntityResult (entityClass = com.baeldung.sqlresultsetmapping.Employee.class), @EntityResult (entityClass = com.baeldung.sqlresultsetmapping.ScheduledDay.class)

5.3. EntityResult Test

Lad os se på EntityResult i aktion:

@Test offentlig ugyldig nårNamedQuery_thenSingleEntityResult () {List medarbejdere = Collections.checkedList (em.createNamedQuery ("Medarbejdere"). GetResultList (), Employee.class); assertEquals (3, medarbejderstørrelse ()); assertTrue (workers.stream (). allMatch (c -> c.getClass () == Medarbejder.klasse)); }

Da resultaterne af flere enheder slutter sig til to enheder, er forespørgselsnotationen på kun en af ​​klasserne forvirrende.

Af den grund definerer vi forespørgslen i testen:

@Test offentlig ugyldig nårNamedQuery_thenMultipleEntityResult () {Query query = em.createNativeQuery ("SELECT e.id, e.name, d.id, d.employeeId, d.dayOfWeek" + "FRA medarbejder e, planlægningsdage d" + "HVOR e .id = d.employeeId "," EmployeeScheduleResults "); Listeresultater = query.getResultList (); assertEquals (4, results.size ()); assertTrue (results.get (0) .længde == 2); Medarbejder emp = (Medarbejder) results.get (1) [0]; ScheduledDay day = (ScheduledDay) results.get (1) [1]; assertTrue (day.getEmployeeId () == emp.getId ()); }

6. Konklusion

I denne vejledning så vi på forskellige muligheder for at bruge SqlResultSetMapping kommentar. SqlResultSetMapping er en vigtig del af Java Persistence API.

Kodestykker kan findes på GitHub.