Een gids voor SqlResultSetMapping

1. Inleiding

In deze gids zullen we kijken naar SqlResultSetMapping, uit de Java Persistence API (JPA).

De kernfunctionaliteit hier omvat het toewijzen van resultatensets van SQL-instructies in de database aan Java-objecten.

2. Installatie

Laten we, voordat we naar het gebruik ervan kijken, wat instellingen uitvoeren.

2.1. Afhankelijkheid van Maven

Onze vereiste Maven-afhankelijkheden zijn Hibernate en H2 Database. Hibernate geeft ons de implementatie van de JPA-specificatie. We gebruiken H2 Database voor een in-memory database.

2.2. Database

Vervolgens maken we twee tabellen zoals hier te zien is:

MAAK TABEL MEDEWERKER (id BIGINT, naam VARCHAR (10));

De WERKNEMER tabel slaat één resultaat op Entiteit voorwerp. SCHEDULE_DAYS bevat records die zijn gekoppeld aan de WERKNEMER tafel bij de kolom werknemer-ID:

MAAK TABEL SCHEDULE_DAYS (id IDENTITY, employeeId BIGINT, dayOfWeek VARCHAR (10));

Een script voor het maken van gegevens is te vinden in de code voor deze handleiding.

2.3. Entiteitsobjecten

Onze Entiteit objecten moeten er ongeveer hetzelfde uitzien:

@Entity openbare klasse Werknemer {@Id privé Lange id; private String naam; }

Entiteit objecten kunnen een andere naam hebben dan databasetabellen. We kunnen de klas annoteren met @Tafel om ze expliciet in kaart te brengen:

@Entity @Table (name = "SCHEDULE_DAYS") openbare klasse ScheduledDay {@Id @GeneratedValue privé Lange id; privé Long employeeId; privé String dayOfWeek; }

3. Scalaire mapping

Nu we gegevens hebben, kunnen we de queryresultaten in kaart brengen.

3.1. ColumnResult

Terwijl SqlResultSetMapping en Vraag annotaties werken aan Opslagplaats klassen gebruiken we de annotaties op een Entiteit class in dit voorbeeld.

Elke SqlResultSetMapping annotatie vereist slechts één eigenschap, naam. Zonder een van de lidtypen wordt er echter niets in kaart gebracht. De lidtypen zijn ColumnResult, ConstructorResult, en EntityResult.

In dit geval, ColumnResult wijst elke kolom toe aan een scalair resultaattype:

@SqlResultSetMapping (name = "FridayEmployeeResult", columns = {@ ColumnResult (name = "employeeId")})

De ColumnResult eigendom naam identificeert de kolom in onze zoekopdracht:

@NamedNativeQuery (name = "FridayEmployees", query = "SELECTEER medewerker-ID FROM schedule_days WHERE dayOfWeek = 'VRIJDAG'", resultSetMapping = "FridayEmployeeResult") 

Let daar op de waarde van resultSetMapping in onze NamedNativeQuery annotatie is belangrijk omdat het overeenkomt met de naam eigendom van onze ResultSetMapping verklaring.

Als gevolg hiervan is het NamedNativeQuery resultaatset wordt toegewezen zoals verwacht. Hetzelfde, Opgeslagen procedure API vereist deze koppeling.

3.2. ColumnResult Test

We hebben enkele Hibernate-specifieke objecten nodig om onze code uit te voeren:

@BeforeAll openbare statische leegte setup () {emFactory = Persistence.createEntityManagerFactory ("java-jpa-geplande-dag"); em = emFactory.createEntityManager (); }

Ten slotte noemen we de benoemde query om onze test uit te voeren:

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

4. Constructor mapping

Laten we eens kijken wanneer we een resultatenset aan een heel object moeten toewijzen.

4.1. ConstructorResult

Net als bij ons ColumnResult we zullen bijvoorbeeld de SqlResultMapping annotatie op onze Entiteit klasse, Geplande dag. Om echter met een constructor in kaart te brengen, moeten we er een maken:

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

De mapping specificeert ook de doelklasse en kolommen (beide vereist):

@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")})})

De volgorde van de ColumnResults is zeer belangrijk. Als kolommen defect zijn, kan de constructor niet worden geïdentificeerd. In ons voorbeeld komt de volgorde overeen met de tabelkolommen, dus het zou eigenlijk niet nodig zijn.

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

Nog een uniek verschil voor ConstructorResult is dat de resulterende object instantiatie als "nieuw" of "onthecht". Het in kaart gebracht Entiteit zal in de ontkoppelde staat zijn als er een overeenkomende primaire sleutel bestaat in het EntityManager anders is het nieuw.

Soms kunnen we runtime-fouten tegenkomen vanwege niet-overeenkomende SQL-datatypes met Java-datatypes. Daarom kunnen we het expliciet aangeven bij type.

4.2. ConstructorResult Test

Laten we de ConstructorResult in een unit-test:

@Test openbare leegte whenNamedQuery_thenConstructorResult () {Lijst 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. Entiteitstoewijzing

Tot slot, voor een eenvoudige entiteitstoewijzing met minder code, laten we eens kijken naar EntityResult.

5.1. Enkele entiteit

EntityResult vereist dat we de entiteitsklasse specificeren, Werknemer. We gebruiken de optionele velden eigenschap voor meer controle. Gecombineerd met Veldresultaat, we kunnen aliassen en velden toewijzen die niet overeenkomen:

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

Nu zou onze vraag de alias-kolom moeten bevatten:

@NamedNativeQuery (naam = "Werknemers", query = "SELECTEER id als werknemersnummer, naam VAN WERKNEMER", resultSetMapping = "WerknemerResultaat")

gelijk aan ConstructorResult, EntityResult vereist een constructor. Een standaard werkt hier echter.

5.2. Meerdere entiteiten

Het in kaart brengen van meerdere entiteiten is vrij eenvoudig als we eenmaal een enkele entiteit in kaart hebben gebracht:

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

5.3. EntityResult Tests

Laten we eens kijken EntityResult in actie:

@Test openbare leegte whenNamedQuery_thenSingleEntityResult () {Lijst werknemers = Collections.checkedList (em.createNamedQuery ("Werknemers"). GetResultList (), Employee.class); assertEquals (3, workers.size ()); assertTrue (workers.stream (). allMatch (c -> c.getClass () == Employee.class)); }

Omdat de resultaten van meerdere entiteiten twee entiteiten samenvoegen, is de annotatie van de query voor slechts één van de klassen verwarrend.

Om die reden definiëren we de vraag in de test:

@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 "); Lijstresultaten = query.getResultList (); assertEquals (4, results.size ()); assertTrue (results.get (0) .length == 2); Werknemer emp = (Werknemer) results.get (1) [0]; ScheduledDay day = (ScheduledDay) results.get (1) [1]; assertTrue (day.getEmployeeId () == emp.getId ()); }

6. Conclusie

In deze handleiding hebben we verschillende opties bekeken voor het gebruik van de SqlResultSetMapping annotatie. SqlResultSetMapping is een belangrijk onderdeel van de Java Persistence API.

Codefragmenten zijn te vinden op GitHub.


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