Részleges adatfrissítés tavaszi adatokkal
1. Bemutatkozás
Tavaszi adatok CrudRespository # mentés kétségtelenül egyszerű, de az egyik funkció hátrány lehet: A táblázat minden oszlopát frissíti. Ilyen az U szemantikája a CRUD-ban, de Mi van, ha PATCH-ot akarunk csinálni helyette?
Ebben az oktatóanyagban a teljes frissítés helyett részleges végrehajtás technikáival és megközelítéseivel foglalkozunk.
2. Probléma
Amint azt korábban mentés() felülír minden egyező entitást a megadott adatokkal, vagyis részleges adatokat nem tudunk megadni. Ez kellemetlenné válhat, különösen nagyobb, sok mezővel rendelkező objektumok esetében.
Ha megnéznénk egy ORM-et, léteznek néhány javítások, például:
- Hibernáltak @DynamicUpdatannotáció, amely dinamikusan újraírja a frissítési lekérdezést
- JPA-k @Oszlop megjegyzés, mivel a frissíthető paraméter
De a következőkben konkrét szándékkal fogunk megközelíteni ezt a problémát: Célunk, hogy felkészítsük entitásainkat a mentés módszer nélkül ORM-re támaszkodva.
3. Esetünk
Először építsünk egy Vevő entitás:
@Entity public class Customer {@Id @GeneratedValue (strategy = GenerationType.AUTO) public long id; public String név; nyilvános vonós telefon; }
Ezután meghatározunk egy egyszerű CRUD adattárat:
@Repository nyilvános felület Az CustomerRepository kiterjeszti a CrudRepository {Customer findById (hosszú id); }
Végül elkészítjük a Vevőszolgálat:
@Service public class CustomerService {@Autowired CustomerRepository repo; public void addCustomer (Karakterlánc neve) {Ügyfél c = új Ügyfél (); c.név = név; repo.save (c); }}
4. Betöltés és mentés megközelítés
Először nézzünk meg egy valószínűleg ismerős megközelítést: az entitásaink betöltése az adatbázisból, majd csak a szükséges mezők frissítése.
Noha ez egyszerű és kézenfekvő, a legegyszerűbb megközelítéseket alkalmazhatjuk.
Vegyünk fel egy módszert a szolgáltatásunkba, hogy frissítsük ügyfeleink elérhetőségi adatait.
public void updateCustomerContacts (hosszú id, String telefon) {Ügyfél myCustomer = repo.findById (id); myCustomer.phone = telefon; repo.save (myCustomer); }
Felhívjuk a findById metódust és beolvassa az egyező entitást, majd folytatjuk és frissítjük a szükséges mezőket, és megőrizzük az adatokat.
Ez az alapvető technika akkor hatékony, ha a frissítendő mezők száma viszonylag kicsi, és entitásaink meglehetősen egyszerűek.
Mi történne több tucat frissítendő mezővel?
4.1. Térképezési stratégia
Amikor az objektumainknak nagyszámú, különböző hozzáférési szintű mezője van, elég gyakori a DTO-minta megvalósítása.
Tegyük fel, hogy több mint százunk van telefon mezők az objektumunkban. Olyan módszer megírása, amely az adatokat a DTO-ból önti az entitásunkhoz, ahogy korábban tettük, zavaró és eléggé fenntarthatatlan lehet.
Ennek ellenére leképezhetjük ezt a kérdést egy leképezési stratégia és különösen a MapStruct végrehajtás.
Hozzunk létre egy CustomerDto:
public class CustomerDto {private long id; public String név; nyilvános vonós telefon; // ... privát karakterlánc telefon99; }
És a CustomerMapper:
@Mapper (componentModel = "spring") nyilvános felület CustomerMapper {void updateCustomerFromDto (CustomerDto dto, @MappingTarget Customer entitás); }
A @MappingTarget az annotáció lehetővé teszi egy meglévő objektum frissítését, ezzel megmentve a sok kód megírásától.
MapStruct van egy @BeanMapping metódekorátor, amelynek segítségével meghatározhatunk egy szabályt, amelyet kihagyunk nulla értékek a leképezési folyamat során. Tegyük hozzá a sajátunkhoz updateCustomerFromDto módszer interfész:
@BeanMapping (nullValuePropertyMappingStrategy = NullValuePropertyMappingStrategy.IGNORE)
Ezzel be tudjuk tölteni a tárolt entitásokat, és egyesíthetjük őket egy DTO-val, mielőtt felhívnánk a JPA-t mentés módszer: valójában csak a módosított értékeket frissítjük.
Tehát adjunk hozzá egy módszert a szolgáltatásunkhoz, amely felhívja a térképészünket:
public void updateCustomer (CustomerDto dto) {Ügyfél myCustomer = repo.findById (dto.id); mapper.updateCustomerFromDto (dto, myCustomer); repo.save (myCustomer); }
Ennek a megközelítésnek az a hátránya, hogy nem léphetünk át nulla értékeket az adatbázisnak egy frissítés során.
4.2. Egyszerűbb entitások
Végül ne feledje, hogy ezt a problémát az alkalmazás tervezési szakaszától kezdve megközelíthetjük.
Alapvető fontosságú meghatározni entitásainkat, hogy a lehető legkisebbek legyenek.
Vessünk egy pillantást a mi Vevő entitás. Mi van, ha egy kicsit strukturáljuk, és kibontjuk az összes telefon mezők a ContactPhone entitások és egy-a-sokhoz viszonyban áll?
@Entity public class CustomerStructured {@Id @GeneratedValue (strategy = GenerationType.AUTO) public Long id; public String név; @OneToMany (fetch = FetchType.EAGER, targetEntity = ContactPhone.class, mappedBy = "customerId") privát lista contactPhones; }
A kód tiszta, és ami még fontosabb, valamit elértünk. Mostantól frissíthetjük entitásainkat anélkül, hogy az összeset be kellene töltenünk és kitöltenünk telefon adat.
Kis és korlátozott entitások kezelése csak a szükséges mezők frissítését teszi lehetővé.
E megközelítés egyetlen kellemetlensége, hogy tudatossággal kell megterveznünk entitásainkat, anélkül, hogy a túlmérnöki csapdába esnénk.
5. Egyéni lekérdezés
Egy másik megközelítés, amelyet megvalósíthatunk, egy egyedi lekérdezés meghatározása a részleges frissítésekhez.
Valójában a JPA két annotációt határoz meg, @ Módosító és @Lekérdezés, amelyek lehetővé teszik számunkra, hogy kifejezetten megírjuk frissítési nyilatkozatunkat.
Most elmondhatjuk alkalmazásunknak, hogyan kell viselkedni egy frissítés során, anélkül, hogy az ORM-re hárítanánk a terhet.
Vegyük fel az egyéni frissítési módszerünket a lerakatba:
@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);
Most átírhatjuk a frissítési módszerünket:
public void updateCustomerContacts (hosszú id, String telefon) {repo.updatePhone (id, telefon); }
Most részleges frissítést tudunk végrehajtani: csupán néhány kódsorral és entitásaink megváltoztatása nélkül elértük célunkat.
Ennek a technikának az a hátránya, hogy meg kell határoznunk egy módszert az objektumunk minden lehetséges részleges frissítésére.
6. Következtetés
A részleges adatfrissítés meglehetősen alapvető művelet; bár rendelkezhetünk ORM-mel a kezelésére, néha nyereséges lehet a teljes irányítás megszerzése.
Amint láttuk, előre betölthetjük adatainkat, majd frissíthetjük őket, vagy meghatározhatjuk az egyéni utasításokat, de ne felejtsük el, hogy tisztában kell lennünk a hátrányokkal, amelyeket ezek a megközelítések jelentenek, és azok leküzdésére.
Szokás szerint a cikk forráskódja elérhető a GitHubon.