Proljetne podatke JPA projekcije

1. Pregled

Kada koristite Spring Data JPA za provedbu sloja postojanosti, spremište obično vraća jednu ili više instanci korijenske klase. Međutim, češće nam ne trebaju sva svojstva vraćenih objekata.

U takvim slučajevima može biti poželjno dohvatiti podatke kao objekte prilagođenih vrsta. Ove vrste odražavaju djelomične poglede na korijensku klasu i sadrže samo svojstva do kojih nam je stalo. Tu projekcije dobro dođu.

2. Početno postavljanje

Prvi korak je postavljanje projekta i popunjavanje baze podataka.

2.1. Ovisnosti Mavena

Za ovisnosti, pogledajte odjeljak 2. ovog vodiča.

2.2. Predmeti entiteta

Definirajmo dvije klase entiteta:

@ Entiteta javna klasa Adresa {@Id private Long id; @OneToOne privatna osoba; privatna država gudača; privatni gudački grad; privatna gudačka ulica; privatni niz zipCode; // geteri i postavljači}

I:

@ Entitet javna klasa Osoba {@ Id privatno Long id; private String firstName; private String lastName; Adresa privatne adrese @OneToOne (mappedBy = "person"); // geteri i postavljači}

Odnos između Osoba i Adresa entiteta dvosmjerno je jedan na jedan: Adresa je strana koja posjeduje, i Osoba je inverzna strana.

Primijetimo u ovom uputstvu, koristimo ugrađenu bazu podataka - H2.

Kada se konfigurira ugrađena baza podataka, Spring Boot automatski generira osnovne tablice za entitete koje smo definirali.

2.3. SQL skripte

Koristimo projekcija-umetanje-podataka.sql skripta za popunjavanje obje pozadinske tablice:

INSERT INTO person (id, first_name, last_name) VRIJEDNOSTI (1, 'John', 'Doe'); INSERT INTO adresa (id, person_id, država, grad, ulica, poštanski broj) VRIJEDNOSTI (1,1, 'CA', 'Los Angeles', 'Standford Ave', '90001');

Da bismo očistili bazu podataka nakon svakog probnog pokretanja, možemo upotrijebiti drugu skriptu, nazvanu projekcija-čišćenje-podataka.sql:

BRISI SA adrese; OBRIŠI OD osobe;

2.4. Test klasa

Da bismo potvrdili da projekcije daju točne podatke, potreban nam je testni razred:

@DataJpaTest @RunWith (SpringRunner.class) @Sql (scripts = "/projection-insert-data.sql") @Sql (scripts = "/projection-clean-up-data.sql", ExecuPhase = AFTER_TEST_METHOD) JpaProjectionIntegracija {// ubrizgana polja i metode ispitivanja}

Uz dane bilješke, Spring Boot stvara bazu podataka, ubrizgava ovisnosti te popunjava i čisti tablice prije i nakon izvršenja svake metode ispitivanja.

3. Projekcije temeljene na sučelju

Pri projiciranju entiteta prirodno je pouzdati se u sučelje jer nećemo trebati osigurati implementaciju.

3.1. Zatvorene projekcije

Osvrćući se na Adresa razreda, možemo vidjeti ima mnoštvo svojstava, ali nisu sva korisna. Na primjer, ponekad je poštanski broj dovoljan da naznači adresu.

Proglasimo projekcijsko sučelje za Adresa razred:

javno sučelje AddressView {String getZipCode (); }

Zatim ga upotrijebite u sučelju spremišta:

javno sučelje AddressRepository proširuje Repozitorij {Lista getAddressByState (stanje niza); }

Lako je uočiti da je definiranje metode spremišta s projekcijskim sučeljem gotovo jednako kao i kod klase entiteta.

Jedina je razlika u tome sučelje za projekciju, umjesto klase entiteta, koristi se kao vrsta elementa u vraćenoj zbirci.

Napravimo brzi test Adresa projekcija:

@Autowired privatni AddressRepository addressRepository; @Test javna prazna kadaUsingClosedProjections_thenViewWithRequiredPropertiesIsReturned () {AddressView addressView = addressRepository.getAddressByState ("CA"). Get (0); assertThat (addressView.getZipCode ()). isEqualTo ("90001"); // ...}

Iza scene, Spring stvara instancu proxyja sučelja za projekciju za svaki objekt entiteta i svi pozivi proxyju prosljeđuju se tom objektu.

Projekcije možemo koristiti rekurzivno. Na primjer, evo projekcijskog sučelja za Osoba razred:

javno sučelje PersonView {String getFirstName (); Niz getLastName (); }

Sad, dodajmo metodu s tipom return PersonView - ugniježđena projekcija - u Adresa projekcija:

javno sučelje AddressView {// ... PersonView getPerson (); }

Primijetite da metoda koja vraća ugniježđenu projekciju mora imati isto ime kao metoda u korijenskoj klasi koja vraća povezani entitet.

Provjerimo ugniježđene projekcije dodavanjem nekoliko izjava u test metodu koju smo upravo napisali:

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

Imajte na umu da rekurzivne projekcije djeluju samo ako prelazimo sa strane koja posjeduje na inverznu stranu. Da to radimo obrnuto, ugniježđena projekcija bila bi postavljena na null.

3.2. Otvorene projekcije

Do ove smo točke prošli kroz zatvorene projekcije, koje ukazuju na sučelja za projekciju čije se metode točno podudaraju s imenima svojstava entiteta.

Postoji još jedna vrsta projekcija zasnovanih na sučelju: otvorene projekcije. Te nam projekcije omogućuju definiranje metoda sučelja s neusporedivim imenima i s povratnim vrijednostima izračunatim tijekom izvođenja.

Vratimo se na Osoba sučelje za projekciju i dodajte novu metodu:

javno sučelje PersonView {// ... @Value ("# {target.firstName + '' + target.lastName}") String getFullName (); }

Argument @Vrijednost napomena je SpEL izraz u kojem se cilj označitelj označava podupirući objekt entiteta.

Sada ćemo definirati drugo sučelje spremišta:

javno sučelje PersonRepository proširuje Repozitorij {PersonView findByLastName (String lastName); }

Da bismo to učinili jednostavnim, umjesto zbirke vraćamo samo jedan projekcijski objekt.

Ovaj test potvrđuje da otvorene projekcije rade prema očekivanjima:

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

Otvorene projekcije imaju nedostatak: Spring Data ne mogu optimizirati izvršavanje upita jer unaprijed ne znaju koja će se svojstva koristiti. Tako, otvorene projekcije trebali bismo koristiti samo kada zatvorene projekcije nisu u stanju ispuniti naše zahtjeve.

4. Projekcije temeljene na klasi

Umjesto da koristimo proxyje, Spring Data nam stvara iz sučelja za projekciju, možemo definirati vlastite klase projekcije.

Na primjer, ovdje je klasa projekcije za Osoba entitet:

javna klasa PersonDto {private String firstName; private String lastName; javno PersonDto (String firstName, String lastName) {this.firstName = firstName; this.lastName = lastName; } // getters, equals i hashCode}

Da bi klasa projekcije radila u tandemu sa sučeljem spremišta, nazivi parametara njezinog konstruktora moraju odgovarati svojstvima klase korijenskog entiteta.

Moramo također definirati jednako i hashCode implementacije - omogućuju Spring Datau da obrađuje projekcijske objekte u zbirci.

Sada, dodajte metodu u Osoba spremište:

javno sučelje PersonRepository proširuje Repozitorij {// ... PersonDto findByFirstName (String firstName); }

Ovaj test potvrđuje našu projekciju temeljenu na nastavi:

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

Primijetite da s pristupom temeljenim na klasi ne možemo koristiti ugniježđene projekcije.

5. Dinamičke projekcije

Klasa entiteta može imati mnogo projekcija. U nekim slučajevima možemo koristiti određenu vrstu, ali u drugim nam može zatrebati druga vrsta. Ponekad trebamo koristiti i samu klasu entiteta.

Definiranje odvojenih sučelja ili metoda spremišta samo za podršku više vrsta povratka je nezgodno. Za rješavanje ovog problema Spring Data pruža bolje rješenje: dinamičke projekcije.

Dinamičke projekcije možemo primijeniti samo deklariranjem metode spremišta pomoću a Razred parametar:

javno sučelje PersonRepository proširuje Repozitorij {// ... T findByLastName (String lastName, vrsta klase); }

Prosljeđivanjem vrste projekcije ili klase entiteta takvoj metodi možemo dohvatiti objekt željenog tipa:

@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 ("Ivan"); assertThat (personDto.getFirstName ()). isEqualTo ("Ivan"); }

6. Zaključak

U ovom smo članku pregledali razne vrste Spring Data JPA projekcija.

Izvorni kôd ovog vodiča dostupan je na GitHub-u. Ovo je Maven projekt i trebao bi biti u stanju pokrenuti kakav jest.


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