Djelomično ažuriranje podataka proljetnim podacima

1. Uvod

Proljetni podaci CrudRespository # spremi je nesumnjivo jednostavno, ali jedna značajka može biti nedostatak: ažurira svaki stupac u tablici. Takva je semantika U u CRUD-u, ali što ako umjesto toga želimo napraviti PATCH?

U ovom ćemo uputstvu pokriti tehnike i pristupe izvođenju djelomičnog umjesto potpunog ažuriranja.

2. Problem

Kao što je već rečeno, uštedjeti() će prebrisati bilo koji podudarni entitet s navedenim podacima, što znači da ne možemo dostaviti djelomične podatke. To može postati nezgodno, posebno za veće objekte s puno polja.

Ako bismo pogledali ORM, postoje neke zakrpe, poput:

  • Hibernate @DynamicUpdatNapomena koja dinamički ponovno upisuje upit za ažuriranje
  • JPA @Stupac napomena, jer možemo onemogućiti ažuriranje određenih stupaca pomoću moguće ažurirati parametar

Ali u nastavku ćemo ovom problemu pristupiti sa određenom namjerom: Naša je svrha pripremiti naše subjekte za uštedjeti metoda bez oslanjanja na ORM.

3. Naš slučaj

Prvo, napravimo a Kupac entitet:

@Entity public class Customer {@Id @GeneratedValue (strategy = GenerationType.AUTO) public long id; naziv javnog niza; javni gudački telefon; } 

Zatim definiramo jednostavno CRUD spremište:

@Repository javno sučelje CustomerRepository proširuje CrudRepository {Customer findById (dugi id); }

Na kraju pripremamo a Služba za korisnike:

@Service javna klasa CustomerService {@Autowired CustomerRepository repo; public void addCustomer (naziv niza) {kupac c = novi kupac (); c.name = ime; repo.save (c); }}

4. Učitajte i spremite pristup

Pogledajmo prvo pristup koji je vjerojatno poznat: učitavanje naših entiteta iz baze podataka, a zatim ažuriranje samo polja koja su nam potrebna.

Iako je ovo jednostavno i očito, to je najjednostavniji pristup koji možemo koristiti.

Dodajmo metodu u našu uslugu za ažuriranje podataka o kontaktima naših kupaca.

javna praznina updateCustomerContacts (dugi ID, String telefon) {Kupac myCustomer = repo.findById (id); myCustomer.phone = telefon; repo.save (myCustomer); }

Nazvat ćemo findById metodom i dohvatimo odgovarajući entitet, zatim nastavljamo i ažuriramo potrebna polja i nastavljamo s podacima.

Ova je osnovna tehnika učinkovita kada je broj polja za ažuriranje relativno malen, a naši su entiteti prilično jednostavni.

Što bi se dogodilo s desecima polja za ažuriranje?

4.1. Mapiranje strategije

Kada naši objekti imaju velik broj polja s različitim razinama pristupa, uobičajeno je primijeniti DTO obrazac.

Sada, pretpostavimo da ih imamo više od stotinu telefon polja u našem objektu. Pisanje metode kojom se podaci iz DTO-a prebacuju u naš entitet, kao što smo to činili i prije, moglo bi biti dosadno i prilično neodrživo.

Ipak, ovaj problem možemo prebroditi koristeći strategiju mapiranja, a posebno pomoću MapStruct provedba.

Stvorimo a CustomerDto:

javna klasa CustomerDto {private long id; naziv javnog niza; javni gudački telefon; // ... private String phone99; }

I također a CustomerMapper:

@Mapper (componentModel = "spring") javno sučelje CustomerMapper {void updateCustomerFromDto (CustomerDto dto, entitet @MappingTarget Customer); }

The @MappingTarget anotacija omogućuje nam ažuriranje postojećeg objekta, spašavajući nas od boli zbog pisanja puno koda.

MapStruct ima @BeanMapping dekorator metoda, koji nam omogućuje definiranje pravila koje treba preskočiti null vrijednosti tijekom postupka mapiranja. Dodajmo ga našem updateCustomerFromDto sučelje metode:

@BeanMapping (nullValuePropertyMappingStrategy = NullValuePropertyMappingStrategy.IGNORE)

Ovim možemo pohraniti entitete i spojiti ih s DTO-om prije pozivanja JPA uštedjeti metoda: zapravo, ažurirat ćemo samo modificirane vrijednosti.

Dakle, dodajmo metodu našoj usluzi koja će pozvati našeg mappera:

javna praznina updateCustomer (CustomerDto dto) {Customer myCustomer = repo.findById (dto.id); mapper.updateCustomerFromDto (dto, myCustomer); repo.save (myCustomer); }

Mana ovog pristupa je što ne možemo proći null vrijednosti u bazu podataka tijekom ažuriranja.

4.2. Jednostavniji entiteti

Napokon, imajte na umu da ovom problemu možemo pristupiti iz faze dizajniranja aplikacije.

Bitno je definirati naše entitete da budu što manji.

Pogledajmo naše Kupac entitet. Što ako to malo strukturiramo i izdvojimo sve telefon polja do ContactPhone entiteta i biti u odnosu jedan prema više?

@Entity javna klasa CustomerStructured {@Id @GeneratedValue (strategy = GenerationType.AUTO) public Long id; naziv javnog niza; @OneToMany (fetch = FetchType.EAGER, targetEntity = ContactPhone.class, mappedBy = "customerId") privatni popis contactPhones; }

Kôd je čist i, što je još važnije, nešto smo postigli. Sada možemo ažurirati svoje entitete bez potrebe za dohvaćanjem i popunjavanjem svih telefon podaci.

Rukovanje malim i ograničenim entitetima omogućuje nam ažuriranje samo potrebnih polja.

Jedina neugodnost ovog pristupa je ta što bismo trebali dizajnirati svoje entitete svjesno, ne ulazeći u zamku preintenziviranja.

5. Prilagođeni upit

Drugi pristup koji možemo primijeniti je definiranje prilagođenog upita za djelomična ažuriranja.

U stvari, JPA definira dvije bilješke, @Modificiranje i @Query, koji nam omogućuju da eksplicitno napišemo izjavu o ažuriranju.

Sada našoj aplikaciji možemo reći kako se ponašati tijekom ažuriranja, a da ne ostavlja teret na ORM-u.

Dodajmo našu prilagođenu metodu ažuriranja u spremište:

@Modifying @Query ("update Customer u set u.phone =: phone where u.id =: id") void updatePhone (@Param (value = "id") long id, @Param (value = "phone") String telefon); 

Sada možemo prepisati našu metodu ažuriranja:

javna praznina updateCustomerContacts (dugi ID, String telefon) {repo.updatePhone (id, telefon); } 

Sada smo u mogućnosti izvršiti djelomično ažuriranje: sa samo nekoliko redaka koda i bez mijenjanja naših entiteta postigli smo svoj cilj.

Nedostatak ove tehnike je taj što ćemo morati definirati metodu za svako moguće djelomično ažuriranje našeg objekta.

6. Zaključak

Djelomično ažuriranje podataka prilično je temeljna operacija; iako možemo imati svoj ORM da to riješi, ponekad bi moglo biti isplativo dobiti potpunu kontrolu nad njim.

Kao što smo vidjeli, možemo unaprijed učitati svoje podatke, a zatim ih ažurirati ili definirati naše prilagođene izjave, ali ne zaboravite biti svjesni nedostataka koje ovi pristupi podrazumijevaju i kako ih prevladati.

Kao i obično, izvorni kod za ovaj članak dostupan je na GitHubu.