Sprievodca po SqlResultSetMapping

1. Úvod

V tejto príručke sa pozrieme na SqlResultSetMapping, z rozhrania Java Persistence API (JPA).

Medzi základné funkcie tu patrí mapovanie množín výsledkov z príkazov databázy SQL do objektov Java.

2. Inštalácia

Než sa pozrieme na jeho použitie, urobme nejaké nastavenie.

2.1. Maven závislosť

Naše požadované závislosti Maven sú Hibernate a H2 Database. Režim dlhodobého spánku nám poskytuje implementáciu špecifikácie JPA. Pre databázu v pamäti používame databázu H2.

2.2. Databáza

Ďalej vytvoríme dve tabuľky, ako je vidieť tu:

VYTVORIŤ TABUĽKU ZAMESTNANCA (id BIGINT, meno VARCHAR (10));

The ZAMESTNANEC tabuľka ukladá jeden výsledok Subjekt objekt. SCHEDULE_DAYS obsahuje záznamy spojené s ZAMESTNANEC tabuľka pri stĺpci zamestnanecké ID:

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

Skript na vytváranie údajov nájdete v kóde tejto príručky.

2.3. Objekty entity

Náš Subjekt objekty by mali vyzerať podobne:

@Entity public class Zamestnanec {@Id private Long id; súkromné ​​meno reťazca; }

Subjekt objekty môžu byť pomenované inak ako databázové tabuľky. Triedu môžeme anotovať pomocou @Tabuľka ich výslovne zmapovať:

@Entity @Table (name = "SCHEDULE_DAYS") verejná trieda ScheduledDay {@Id @GeneratedValue private Long id; private Long employeeId; private String dayOfWeek; }

3. Skalárne mapovanie

Teraz, keď máme údaje, môžeme začať mapovať výsledky dotazov.

3.1. ColumnResult

Zatiaľ čo SqlResultSetMapping a Dopyt anotácie fungujú Úložisko triedy tiež používame anotácie na Subjekt triedy v tomto príklade.

Každý SqlResultSetMapping anotácia vyžaduje iba jednu vlastnosť, názov. Bez jedného z typov členov sa však nič nezmapuje. Typy členov sú ColumnResult, ConstructorResulta EntityResult.

V tomto prípade, ColumnResult mapuje akýkoľvek stĺpec na skalárny typ výsledku:

@SqlResultSetMapping (name = "FridayEmployeeResult", stĺpce = {@ ColumnResult (name = "employeeId")})

The ColumnResult nehnuteľnosť názov identifikuje stĺpec v našom dotaze:

@NamedNativeQuery (name = "FridayEmployees", query = "VYBERTE zamestnanca FROM plánovaných dní KDE dayOfWeek = 'PIATOK'", resultSetMapping = "FridayEmployeeResult") 

Poznač si to hodnota resultSetMapping v našom NamedNativeQuery anotácia je dôležité, pretože sa zhoduje s názov majetok z nášho ResultSetMapping vyhlásenie.

Výsledkom je, že NamedNativeQuery množina výsledkov je mapovaná podľa očakávania. Podobne, StoredProcedure API vyžaduje toto priradenie.

3.2. ColumnResult Test

Na spustenie nášho kódu budeme potrebovať niekoľko objektov špecifických pre režim dlhodobého spánku:

@BeforeAll public static void setup () {emFactory = Persistence.createEntityManagerFactory ("java-jpa-scheduled-day"); em = emFactory.createEntityManager (); }

Nakoniec zavoláme pomenovaný dotaz, aby sme spustili náš test:

@Test public void whenNamedQuery_thenColumnResult () {List employeeIds = em.createNamedQuery ("FridayEmployees"). GetResultList (); assertEquals (2, employeeIds.size ()); }

4. Mapovanie konštruktorov

Poďme sa pozrieť na to, kedy je potrebné mapovať výslednú sadu na celý objekt.

4.1. ConstructorResult

Podobne ako u nás ColumnResult napríklad pridáme SqlResultMapping anotácia k nášmu Subjekt trieda, Naplánovaný deň. Aby sme však mohli mapovať pomocou konštruktora, musíme si ho vytvoriť:

public ScheduledDay (Long id, Long employeeId, Integer hourIn, Integer hourOut, String dayofWeek) {this.id = id; this.employeeId = employeeId; this.dayOfWeek = dayofWeek; }

Mapovanie tiež určuje cieľovú triedu a stĺpce (obidva sú povinné):

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

Poradie Výsledky stĺpca je veľmi dôležité. Ak sú stĺpce mimo poradia, konštruktor sa nepodarí identifikovať. V našom príklade sa zoradenie zhoduje so stĺpcami tabuľky, takže by to vlastne nebolo potrebné.

@NamedNativeQuery (name = "Schedules", query = "SELECT * FROM schedule_days WHERE employeeId = 8", resultSetMapping = "ScheduleResult")

Ďalším jedinečným rozdielom pre ConstructorResult je, že výsledná inštancia objektu ako „nová“ alebo „odpojená“. Zmapované Subjekt bude v odpojenom stave, keď bude v EntityManager inak bude nový.

Niekedy sa môžeme stretnúť s runtime chybami z dôvodu nesúladu dátových typov SQL s dátovými typmi Java. Preto to môžeme výslovne deklarovať pomocou typu.

4.2. ConstructorResult Test

Poďme vyskúšať ConstructorResult pri jednotkovej skúške:

@Test public void whenNamedQuery_thenConstructorResult () {List scheduleDays = Collections.checkedList (em.createNamedQuery ("Schedules", ScheduledDay.class) .getResultList (), ScheduledDay.class); assertEquals (3, scheduleDays.size ()); assertTrue (scheduleDays.stream (). allMatch (c -> c.getEmployeeId (). longValue () == 3)); }

5. Mapovanie entít

Nakoniec, pre jednoduché mapovanie entít s menším počtom kódov, sa pozrime na EntityResult.

5.1. Jeden subjekt

EntityResult vyžaduje, aby sme určili triedu entít, Zamestnanec. Používame voliteľné polia vlastnosť pre väčšiu kontrolu. Kombinované s FieldResult, môžeme mapovať aliasy a polia, ktoré sa nezhodujú:

@SqlResultSetMapping (name = "EmployeeResult", entity = {@EntityResult (entityClass = com.baeldung.sqlresultsetmapping.Employee.class, fields = {@FieldResult (name = "id", column = "employeeNumber"), @FieldResult (name) = "meno", stĺpec = "meno")})})

Náš dopyt by teraz mal obsahovať aliasovaný stĺpec:

@NamedNativeQuery (name = "Zamestnanci", dotaz = "VYBERTE ID ako číslo zamestnanca, meno OD ZAMESTNANCA", resultSetMapping = "EmployeeResult")

Podobne ako ConstructorResult, EntityResult vyžaduje konštruktéra. Tu však funguje predvolený.

5.2. Viac entít

Mapovanie viacerých entít je celkom jednoduché, keď už máme namapovanú jednu entitu:

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

5.3. EntityResult Skúšky

Poďme sa na to pozrieť EntityResult v akcii:

@Test public void whenNamedQuery_thenSingleEntityResult () {Zoznam zamestnancov = Collections.checkedList (em.createNamedQuery ("Zamestnanci"). GetResultList (), Employee.class); assertEquals (3, zamestnanci.size ()); assertTrue (Zamestnanci.stream (). allMatch (c -> c.getClass () == Zamestnanec.trieda)); }

Pretože výsledky viacerých entít spájajú dve entity, anotácia dotazu iba v jednej z tried je mätúca.

Z tohto dôvodu definujeme dopyt v teste:

@Test public void whenNamedQuery_thenMultipleEntityResult () {Query query = em.createNativeQuery ("SELECT e.id, e.name, d.id, d.employeeId, d.dayOfWeek" + "FROM employee e, schedule_days d" + "WHERE e .id = d.employeeId "," EmployeeScheduleResults "); Zoznam výsledkov = query.getResultList (); assertEquals (4, results.size ()); assertTrue (results.get (0) .length == 2); Zamestnanec emp = (Zamestnanec) results.get (1) [0]; ScheduledDay day = (ScheduledDay) results.get (1) [1]; assertTrue (day.getEmployeeId () == emp.getId ()); }

6. Záver

V tejto príručke sme sa pozreli na rôzne možnosti použitia súboru SqlResultSetMapping anotácia. SqlResultSetMapping je kľúčovou súčasťou rozhrania Java Persistence API.

Útržky kódu nájdete na GitHub.


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