Jarné údajové projekcie JPA

1. Prehľad

Pri použití Spring Data JPA na implementáciu vrstvy perzistencie úložisko zvyčajne vráti jednu alebo viac inštancií triedy root. Častejšie však nepotrebujeme všetky vlastnosti vrátených objektov.

V takýchto prípadoch môže byť žiaduce načítať údaje ako objekty prispôsobených typov. Tieto typy odrážajú čiastočné pohľady na koreňovú triedu, ktoré obsahujú iba vlastnosti, na ktorých nám záleží. Tu prichádzajú vhod projekcie.

2. Počiatočné nastavenie

Prvým krokom je nastavenie projektu a osadenie databázy.

2.1. Maven závislosti

Závislosti nájdete v časti 2 tohto tutoriálu.

2.2. Triedy entít

Definujme dve triedy entít:

@Entity public class Adresa {@Id private Long id; @OneToOne súkromná osoba; súkromný štát reťazca; súkromné ​​mesto String; súkromná ulica String; súkromný reťazec zipCode; // zakladatelia a zakladatelia}

A:

@Entity verejná trieda Osoba {@Id súkromná Long id; private String meno; private String priezvisko; @OneToOne (mappedBy = "osoba") súkromná adresa; // zakladatelia a zakladatelia}

Vzťah medzi Osoba a Adresa subjekty je obojsmerný jedna k jednej: Adresa je vlastniacou stranou a Osoba je opačná strana.

Všimnite si v tomto tutoriále, že používame vloženú databázu - H2.

Keď je nakonfigurovaná vložená databáza, Spring Boot automaticky generuje podkladové tabuľky pre entity, ktoré sme definovali.

2.3. Skripty SQL

Používame projection-insert-data.sql skript na vyplnenie obidvoch podporných tabuliek:

INSERT INTO person (id, first_name, last_name) VALUES (1, 'John', 'Doe'); INSERT INTO address (id, person_id, state, city, street, zip_code) VALUES (1,1, 'CA', 'Los Angeles', 'Standford Ave', '90001');

Na vyčistenie databázy po každom testovacom behu môžeme použiť iný skript s názvom projection-clean-up-data.sql:

ODSTRÁNIŤ Z adresy; ODSTRÁNIŤ Z osoby;

2.4. Skúšobná trieda

Na potvrdenie, že projekcie poskytujú správne údaje, potrebujeme testovaciu triedu:

@DataJpaTest @RunWith (SpringRunner.class) @Sql (scripts = "/projection-insert-data.sql") @Sql (scripts = "/projection-clean-up-data.sql", executionPhase = AFTER_TEST_METHOD) verejná trieda JpaProjectionIntegration {// vložené polia a testovacie metódy}

S danými anotáciami Spring Boot vytvorí databázu, vloží do nej závislosti a naplní a vyčistí tabuľky pred a po vykonaní každej testovacej metódy.

3. Projekcie založené na rozhraní

Pri projektovaní entity je prirodzené spoliehať sa na rozhranie, pretože nebudeme musieť poskytovať implementáciu.

3.1. Uzavreté projekcie

Pri pohľade späť na Adresa triedy, vidíme má veľa vlastností, ale nie všetky sú užitočné. Napríklad na označenie adresy niekedy stačí PSČ.

Vyhlásime projekčné rozhranie pre Adresa trieda:

verejné rozhranie AddressView {String getZipCode (); }

Potom ho použite v rozhraní úložiska:

verejné rozhranie AddressRepository rozširuje úložisko {List getAddressByState (stav reťazca); }

Je ľahké vidieť, že definovanie metódy úložiska s projekčným rozhraním je skoro rovnaké ako v prípade triedy entít.

Rozdiel je iba v tom ako typ prvku vo vrátenej kolekcii sa použije projekčné rozhranie, a nie trieda entít.

Poďme urobiť rýchly test Adresa projekcia:

@Autowired private AddressRepository addressRepository; @Test public void whenUsingClosedProjections_thenViewWithRequiredPropertiesIsReturned () {AddressView addressView = addressRepository.getAddressByState ("CA"). Get (0); assertThat (addressView.getZipCode ()). isEqualTo ("90001"); // ...}

V zákulisí, Jar vytvára inštanciu proxy projekčného rozhrania pre každý objekt entity a všetky volania na proxy sa presmerujú na tento objekt.

Projekcie môžeme použiť rekurzívne. Napríklad tu je projekčné rozhranie pre Osoba trieda:

verejné rozhranie PersonView {String getFirstName (); Reťazec getLastName (); }

Teraz pridajme metódu s návratovým typom PersonView - vnorená projekcia - v Adresa projekcia:

verejné rozhranie AddressView {// ... PersonView getPerson (); }

Všimnite si, že metóda, ktorá vracia vnorenú projekciu, musí mať rovnaký názov ako metóda v koreňovej triede, ktorá vracia súvisiacu entitu.

Poďme overiť vnorené projekcie pridaním niekoľkých príkazov k testovacej metóde, ktorú sme práve napísali:

// ... PersonView personView = addressView.getPerson (); assertThat (personView.getFirstName ()). isEqualTo ("John"); assertThat (personView.getLastName ()). isEqualTo ("Doe");

Poznač si to rekurzívne projekcie fungujú, iba ak prechádzame z vlastniacej strany na inverznú. Keby sme to robili opačne, vnorená projekcia by bola nastavená na nulový.

3.2. Otvorené projekcie

Až do tohto bodu sme prešli uzavretými projekciami, ktoré označujú projekčné rozhrania, ktorých metódy sa presne zhodujú s názvami vlastností entít.

Existuje ďalší druh projekcií založených na rozhraní: otvorené projekcie. Tieto projekcie nám umožňujú definovať metódy rozhrania s bezkonkurenčnými názvami a s návratovými hodnotami vypočítanými za behu.

Vráťme sa k Osoba projekčné rozhranie a pridať novú metódu:

verejné rozhranie PersonView {// ... @Value ("# {target.firstName + '' + target.lastName}") Reťazec getFullName (); }

Argument k @Hodnota anotácia je výraz SpEL, v ktorom cieľ designátor označuje objekt podpornej entity.

Teraz definujeme ďalšie rozhranie úložiska:

verejné rozhranie PersonRepository rozširuje úložisko {PersonView findByLastName (reťazec priezvisko); }

Aby sme to zjednodušili, vrátime namiesto kolekcie iba jeden projekčný objekt.

Tento test potvrdzuje, že otvorené projekcie fungujú podľa očakávania:

@Autowired private PersonRepository personRepository; @Testpublic void whenUsingOpenProjections_thenViewWithRequiredPropertiesIsReturned () {PersonView personView = personRepository.findByLastName ("Doe"); assertThat (personView.getFullName ()). isEqualTo ("John Doe"); }

Otvorené projekcie majú nevýhodu: Spring Data nemôže optimalizovať vykonávanie dotazu, pretože vopred nevie, ktoré vlastnosti sa použijú. Teda otvorené projekcie by sme mali používať, iba ak uzavreté projekcie nie sú schopné zvládnuť naše požiadavky.

4. Projekcie založené na triedach

Namiesto použitia proxy pre nás Spring Data vytvára z projekčných rozhraní, môžeme definovať svoje vlastné triedy projekcie.

Napríklad tu je projekčná trieda pre Osoba subjekt:

verejná trieda PersonDto {private String firstName; private String priezvisko; public PersonDto (reťazec meno, reťazec priezvisko) {this.firstName = meno; this.lastName = priezvisko; } // getre, rovne a hashCode}

Aby trieda projekcie fungovala v tandeme s rozhraním úložiska, musia sa názvy parametrov jej konštruktora zhodovať s vlastnosťami triedy koreňovej entity.

Musíme tiež definovať rovná sa a hashCode implementácie - umožňujú spoločnosti Spring Data spracovávať projekčné objekty v kolekcii.

Teraz pridajme metódu do Osoba Úložisko:

verejné rozhranie PersonRepository rozširuje úložisko {// ... PersonDto findByFirstName (reťazec firstName); }

Tento test overuje našu projekciu založenú na triede:

@Test public void whenUsingClassBasedProjections_thenDtoWithRequiredPropertiesIsReturned () {PersonDto personDto = personRepository.findByFirstName ("John"); assertThat (personDto.getFirstName ()). isEqualTo ("John"); assertThat (personDto.getLastName ()). isEqualTo ("Doe"); }

Všimnite si, že pri prístupe založenom na triedach nemôžeme používať vnorené projekcie.

5. Dynamické projekcie

Trieda entity môže mať veľa projekcií. V niektorých prípadoch môžeme použiť určitý typ, ale v iných prípadoch môžeme potrebovať iný typ. Niekedy musíme použiť aj samotnú triedu entít.

Definovanie samostatných rozhraní alebo metód úložiska iba na podporu viacerých typov návratov je ťažkopádne. Na riešenie tohto problému poskytuje Spring Data lepšie riešenie: dynamické projekcie.

Dynamické projekcie môžeme použiť iba vyhlásením metódy úložiska s a Trieda parameter:

verejné rozhranie PersonRepository rozširuje úložisko {// ... T findByLastName (reťazec priezvisko, typ triedy); }

Pri odovzdaní typu projekcie alebo triedy entity takejto metóde môžeme načítať objekt požadovaného typu:

@Test public void whenUsingDynamicProjections_thenObjectWithRequiredPropertiesIsReturned () {Person person = personRepository.findByLastName ("Doe", Person.class); PersonView personView = personRepository.findByLastName ("Doe", PersonView.class); PersonDto personDto = personRepository.findByLastName ("Doe", PersonDto.class); assertThat (person.getFirstName ()). isEqualTo ("John"); assertThat (personView.getFirstName ()). isEqualTo ("John"); assertThat (personDto.getFirstName ()). isEqualTo ("John"); }

6. Záver

V tomto článku sme si prešli rôzne typy projekcií Spring Data JPA.

Zdrojový kód tohto tutoriálu je k dispozícii na GitHub. Toto je projekt Maven a mal by byť schopný bežať tak, ako je.


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