Delvis dataoppdatering med vårdata

1. Introduksjon

Spring Data's CrudRespository # lagre er utvilsomt enkelt, men en funksjon kan være en ulempe: Den oppdaterer hver kolonne i tabellen. Slik er semantikken til U i CRUD, men hva om vi ønsker å lage en lapp i stedet?

I denne opplæringen skal vi dekke teknikker og tilnærminger for å utføre en delvis i stedet for en fullstendig oppdatering.

2. Problem

Som nevnt tidligere, lagre() vil overskrive alle samsvarende enheter med oppgitte data, noe som betyr at vi ikke kan levere delvis data. Det kan bli upraktisk, spesielt for større gjenstander med mange felt.

Hvis vi ser på en ORM, finnes det noen oppdateringer, som:

  • Dvalemodus @DynamicUpdate-kommentar, som dynamisk skriver om oppdateringsspørsmålet
  • JPA-er @Kolonne kommentar, ettersom vi ikke kan tillate oppdateringer om bestemte kolonner ved hjelp av kan oppdateres parameter

Men i det følgende skal vi nærme oss dette problemet med spesifikk hensikt: Vårt formål er å forberede enhetene våre for lagre metode uten å stole på en ORM.

3. Vår sak

La oss først bygge en Kunde enhet:

@Entity offentlig klasse kunde {@Id @GeneratedValue (strategi = GenerationType.AUTO) offentlig lang id; offentlig streng navn; offentlig String telefon; } 

Deretter definerer vi et enkelt CRUD-depot:

@Repository offentlig grensesnitt CustomerRepository utvider CrudRepository {Customer findById (lang id); }

Til slutt forbereder vi en Kundeservice:

@Service offentlig klasse CustomerService {@Autowired CustomerRepository repo; public void addCustomer (String name) {Customer c = new Customer (); c.name = navn; repo.save (c); }}

4. Load and Save Approach

La oss først se på en tilnærming som sannsynligvis er kjent: å laste inn enhetene våre fra databasen og deretter bare oppdatere feltene vi trenger.

Selv om dette er enkelt og åpenbart, er det de enkleste tilnærmingene vi kan bruke.

La oss legge til en metode i tjenesten vår for å oppdatere kontaktdataene til kundene våre.

offentlig ugyldig oppdateringCustomerContacts (lang id, strengtelefon) {Kund myCustomer = repo.findById (id); myCustomer.phone = telefon; repo.save (minKunde); }

Vi ringer findById metode og hente den samsvarende enheten, så fortsetter vi og oppdaterer de nødvendige feltene og vedvarer dataene.

Denne grunnleggende teknikken er effektiv når antall felt som skal oppdateres er relativt lite, og enhetene våre er ganske enkle.

Hva ville skje med dusinvis av felt å oppdatere?

4.1. Kartleggingsstrategi

Når objektene våre har et stort antall felt med forskjellige tilgangsnivåer, er det ganske vanlig å implementere DTO-mønsteret.

Anta at vi har mer enn hundre telefonen felt i objektet vårt. Å skrive en metode som skjenker dataene fra DTO til enheten vår, som vi gjorde før, kan være plagsom og ganske uvedlikeholdelig.

Likevel kan vi komme over dette problemet ved hjelp av en kartleggingsstrategi, og spesielt med MapStruct gjennomføring.

La oss lage en CustomerDto:

offentlig klasse CustomerDto {privat lang id; offentlig streng navn; offentlig String telefon; // ... privat streng telefon99; }

Og også en CustomerMapper:

@Mapper (componentModel = "spring") offentlig grensesnitt CustomerMapper {void updateCustomerFromDto (CustomerDto dto, @MappingTarget Customer entity); }

De @MappingTarget kommentar lar oss oppdatere et eksisterende objekt, og redde oss fra smerten ved å skrive mye kode.

MapStruct har en @BeanMapping metode dekoratør, som lar oss definere en regel å hoppe over null verdier under kartleggingsprosessen. La oss legge det til vårt updateCustomerFromDto metode grensesnitt:

@BeanMapping (nullValuePropertyMappingStrategy = NullValuePropertyMappingStrategy.IGNORE)

Med dette kan vi laste lagrede enheter og slå dem sammen med en DTO før vi ringer til JPA lagre metode: faktisk oppdaterer vi bare de modifiserte verdiene.

Så la oss legge til en metode i tjenesten vår, som vil kalle kartleggeren vår:

offentlig tomrom updateCustomer (CustomerDto dto) {Customer myCustomer = repo.findById (dto.id); mapper.updateCustomerFromDto (dto, myCustomer); repo.save (minKunde); }

Ulempen med denne tilnærmingen er at vi ikke kan passere null verdier til databasen under en oppdatering.

4.2. Enklere enheter

Til slutt, husk at vi kan nærme oss dette problemet fra designfasen til en applikasjon.

Det er viktig å definere enhetene våre for å være så små som mulig.

La oss ta en titt på vår Kunde enhet. Hva om vi strukturerer det litt, og trekker ut alt telefonen felt til Kontakt telefon enheter og være i et en-til-mange forhold?

@Entity offentlig klasse CustomerStructured {@Id @GeneratedValue (strategi = GenerationType.AUTO) offentlig Lang id; offentlig streng navn; @OneToMany (fetch = FetchType.EAGER, targetEntity = ContactPhone.class, mappedBy = "customerId") private List contactPhones; }

Koden er ren, og enda viktigere, vi oppnådde noe. Nå kan vi oppdatere enhetene våre uten å måtte hente og fylle alle telefonen data.

Håndtering av små og avgrensede enheter lar oss bare oppdatere de nødvendige feltene.

Den eneste ulempen med denne tilnærmingen er at vi skal utforme enhetene våre med bevissthet, uten å falle i fellen av overingeniør.

5. Tilpasset spørring

En annen tilnærming vi kan implementere er å definere et tilpasset spørsmål for delvise oppdateringer.

Faktisk definerer JPA to merknader, @Modifying og @Spørsmål, som lar oss skrive oppdateringserklæringen eksplisitt.

Vi kan nå fortelle søknaden vår hvordan vi skal oppføre oss under en oppdatering, uten å legge byrden på ORM.

La oss legge til vår tilpassede oppdateringsmetode i depotet:

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

Nå kan vi skrive om oppdateringsmetoden vår:

offentlig ugyldig oppdateringCustomerContacts (lang id, strengtelefon) {repo.updatePhone (id, telefon); } 

Nå er vi i stand til å utføre en delvis oppdatering: med bare noen få kodelinjer og uten å endre enhetene våre, har vi nådd vårt mål.

Ulempen med denne teknikken er at vi må definere en metode for hver mulig delvis oppdatering av objektet vårt.

6. Konklusjon

Den delvise dataoppdateringen er ganske grunnleggende; mens vi kan ha vår ORM til å håndtere det, kan det noen ganger være lønnsomt å få full kontroll over det.

Som vi har sett, kan vi forhåndslaste dataene våre og deretter oppdatere dem eller definere våre tilpassede utsagn, men husk å være klar over ulempene som disse tilnærmingene innebærer og hvordan vi kan overvinne dem.

Som vanlig er kildekoden for denne artikkelen tilgjengelig på GitHub.


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