Spring Data JPA @Query

1. Áttekintés

A Spring Data számos módon meghatározhat egy lekérdezést, amelyet végre tudunk hajtani. Ezek egyike a @Lekérdezés annotáció.

Ebben az oktatóanyagban bemutatjuk hogyan kell használni a @Lekérdezés annotáció a Spring Data JPA-ban JPQL és natív SQL lekérdezések végrehajtásához.

Azt is megmutatjuk, hogyan lehet dinamikus lekérdezést létrehozni, amikor a @Lekérdezés a kommentár nem elég.

2. Válassza a Lekérdezés lehetőséget

Annak érdekében, hogy definiálhassuk az SQL-t egy Spring Data-lerakat-módszer végrehajtásához, megtehetjük jegyezze fel a módszert a @Lekérdezés annotáció - annak érték attribútum a végrehajtandó JPQL-t vagy SQL-t tartalmazza.

A @Lekérdezés az annotáció elsőbbséget élvez a megnevezett lekérdezésekkel szemben, amelyekkel a jegyzetek szerepelnek @NévQuery vagy egy an-ban definiált orm.xml fájl.

Jó megközelítés, ha a lekérdezésdefiníciót közvetlenül a módszer fölé helyezzük az adattárba, nem pedig a tartományi modellünkbe, nevezett lekérdezésekként. Az adattár felelős a kitartásért, ezért jobb hely ezeknek a definícióknak a tárolására.

2.1. JPQL

Alapértelmezés szerint a lekérdezés meghatározása JPQL-t használ.

Nézzünk meg egy egyszerű repository módszert, amely aktívvá válik Felhasználó entitások az adatbázisból:

@Query ("SELECT u FROM User u WHERE u.status = 1") Gyűjtemény findAllActiveUsers (); 

2.2. Anyanyelvi

A natív SQL-t is használhatjuk a lekérdezés meghatározásához. Csak annyit kell tennünk állítsa be a nativeQuery tulajdonít neki igaz és definiálja a natív SQL lekérdezést a érték a kommentár attribútuma:

@Query (érték = "KIVÁLASZTÁS * FELHASZNÁLÓKTÓL u WHERE u.status = 1", nativeQuery = true) Gyűjtemény findAllActiveUsersNative (); 

3. Határozza meg a sorrendet egy lekérdezésben

Átadhatunk egy további típusú paramétert Fajta egy Spring Data módszer deklarációhoz, amely rendelkezik a @Lekérdezés annotáció. Lefordítják a RENDEZÉS záradék, amely átkerül az adatbázisba.

3.1. Rendezés a JPA által biztosított és levezetett módszerekhez

Azokról a módszerekről, amelyeket kiszedünk a dobozból, mint pl findAll (rendezés) vagy amelyek a módszeres aláírások elemzésével jönnek létre, csak objektumtulajdonságokat használhatunk a rendezésünk meghatározásához:

userRepository.findAll (új rendezés (Sort.Direction.ASC, "név")); 

Most képzelje el, hogy egy név tulajdonságának hossza szerint akarunk rendezni:

userRepository.findAll (új rendezés ("LENGTH (név)")); 

Amikor végrehajtjuk a fenti kódot, kivételt kapunk:

org.springframework.data.mapping.PropertyReferenceException: Nem található tulajdonság LENGTH (név) a Felhasználó típushoz!

3.2. JPQL

Amikor a lekérdezés meghatározásához JPQL-t használunk, akkor a Spring Data gond nélkül képes kezelni a rendezést - csak annyit kell tennünk, hogy hozzáadunk egy típusú paramétert Fajta:

@Query (value = "SELECT u FROM User u") List findAllUsers (Rendezés rendezése); 

Hívhatjuk ezt a módszert és átadhatjuk a Fajta paraméter, amely az eredményt a név tulajdona Felhasználó tárgy:

userRepository.findAllUsers (új Rendezés ("név"));

És mert mi használtuk a @Lekérdezés annotációval, ugyanazt a módszert használhatjuk a rendezett lista megszerzéséhez Felhasználók nevük hossza szerint:

userRepository.findAllUsers (JpaSort.unsafe ("LENGTH (név)")); 

Döntő fontosságú, hogy használjuk JpaSort.unsafe () létrehozni a Fajta objektum példány.

Amikor használjuk:

új rendezés ("LENGTH (név)"); 

akkor pontosan ugyanazt a kivételt kapjuk, mint amit fentebb láttunk a Találd meg mindet() módszer.

Amikor a Spring Data felfedezi a nem biztonságosakat Fajta rendeljen egy módszert, amely a @Lekérdezés megjegyzés, akkor csak a rendezési záradékot csatolja a lekérdezéshez - kihagyja annak ellenőrzését, hogy a rendezni kívánt tulajdonság a tartományi modellhez tartozik-e.

3.3. Anyanyelvi

Amikor az @Lekérdezés az annotáció natív SQL-t használ, akkor nem lehet meghatározni a Fajta.

Ha mégis, kivételt kapunk:

org.springframework.data.jpa.repository.query.InvalidJpaQueryMethodException: Nem használható natív lekérdezés dinamikus rendezéssel és / vagy lapozással

Mint a kivétel mondja, a rendezés nem támogatott natív lekérdezéseknél. A hibaüzenet arra utal, hogy a lapozás is kivételt jelent.

Van azonban egy megoldás, amely lehetővé teszi a lapozást, és ezt a következő szakaszban tárgyaljuk.

4. Lapozás

A lapozás lehetővé teszi, hogy a teljes eredménynek csak egy részhalmazát adjuk vissza a Oldal. Ez például akkor hasznos, ha egy weboldalon több adatlapon navigálunk.

A lapozás másik előnye, hogy a szerverről az ügyfélre küldött adatok mennyisége minimálisra csökken. Kisebb adatok elküldésével általában a teljesítmény javulását láthatjuk.

4.1. JPQL

A lapozás használata a JPQL lekérdezés definíciójában egyszerű:

@Query (érték = "SELECT u FROM User u ORDER BY id") oldal findAllUsersWithPagination (lapozható lapozható); 

Áthaladhatunk a PageRequest paraméter az oldal adatainak megszerzéséhez.

A lapozás natív lekérdezéseknél is támogatott, de egy kis további munkát igényel.

4.2. Anyanyelvi

Tudunk engedélyezze a lapozást natív lekérdezéseknél egy további attribútum deklarálásával countQuery.

Ez meghatározza az végrehajtandó SQL-t, hogy megszámolja a sorok számát a teljes eredményben:

@Query (érték = "KIVÁLASZTÁS * FROM felhasználók ORDER BY id" alapján, countQuery = "KIVÁLASZTÁS (*) FROM felhasználóktól", nativeQuery = true) Page findAllUsersWithPagination (lapozható lapozható);

4.3. Spring Data JPA verziók a 2.0.4 előtt

A natív lekérdezések fenti megoldása jól működik a Spring Data JPA 2.0.4 és újabb verzióinál.

Az említett verzió előtt, amikor megpróbálunk végrehajtani egy ilyen lekérdezést, ugyanazt a kivételt kapjuk, amelyet az előző, rendezésről szóló részben ismertettünk.

Ezt leküzdhetjük, ha egy további paramétert adunk a lapozáshoz a lekérdezésünkön belül:

@Query (érték = "KIVÁLASZTÁS * FROM Felhasználóktól RENDELÉS ID \ n-- #pageable \ n", countQuery = "KIVÁLASZTÁS (*) FROM felhasználóktól", nativeQuery = true) Page findAllUsersWithPagination (lapozható lapozható);

A fenti példában hozzáadjuk a „\ n– #pageable \ n” -t a lapozás paraméterének helyőrzőjévé. Ez megmondja a Spring Data JPA-nak, hogyan kell elemezni a lekérdezést és beadni a lapozható paramétert. Ez a megoldás a H2 adatbázis.

Kitértünk arra, hogyan lehet egyszerű kiválasztott lekérdezéseket létrehozni JPQL és natív SQL segítségével. Ezután bemutatjuk a további paraméterek meghatározásának módját.

5. Indexelt lekérdezési paraméterek

Kétféle módon adhatjuk át a metódusparamétereket a lekérdezésünknek: indexelt és elnevezett paraméterek.

Ebben a szakaszban az indexelt paramétereket ismertetjük.

5.1. JPQL

A JPQL-ben indexelt paraméterek esetén a Spring Data meg fogja tenni adja át a metódus paramétereit a lekérdezésnek ugyanabban a sorrendben, ahogyan a metódus deklarációban szerepelnek:

@Query ("SELECT u FROM User u WHERE u.status =? 1") User findUserByStatus (Egész állapot); @Query ("SELECT u FROM User u WHERE u.status =? 1 és u.name =? 2") User findUserByStatusAndName (Egész állapot, Karakterlánc neve); 

A fenti lekérdezésekhez a állapot A metódus paraméter az indexet tartalmazó lekérdezési paraméterhez lesz hozzárendelve 1, és a név A metódus paraméter az indexet tartalmazó lekérdezési paraméterhez lesz hozzárendelve 2.

5.2. Anyanyelvi

A natív lekérdezések indexelt paraméterei pontosan ugyanúgy működnek, mint a JPQL esetében:

@Query (value = "SELECT * FROM Users u WHERE u.status =? 1", nativeQuery = true) Felhasználó findUserByStatusNative (Egész állapot);

A következő szakaszban egy másik megközelítést mutatunk be: a paraméterek átadása néven keresztül.

6. Megnevezett paraméterek

Azt is megtehetjük adja meg a metódus paramétereit a lekérdezésnek megnevezett paraméterek segítségével. Ezeket a @Param annotáció a repository metódus deklaráción belül.

Minden paraméter a következővel lett jelölve @Param a megfelelő JPQL vagy SQL lekérdezési paraméter nevének megfelelő értékű karakterláncnak kell lennie. A megnevezett paraméterekkel rendelkező lekérdezés könnyebben olvasható és kevésbé hajlamos arra az esetre, ha a lekérdezést újra kell dolgozni.

6.1. JPQL

Mint fent említettük, a @Param annotáció a metódusdeklarációban, hogy megfeleljen a JPQL-ben név szerint definiált paramétereknek a metódusdeklaráció paramétereivel:

@Query ("SELECT u FROM User u WHERE u.status =: status and u.name =: name") User findUserByStatusAndNameNamedParams (@Param ("status") Integer status, @Param ("name") String name); 

Ne feledje, hogy a fenti példában meghatároztuk az SQL lekérdezés és metódus paramétereinket, hogy ugyanazok a nevek legyenek, de ez nem szükséges, amíg az értékláncok megegyeznek:

@Query ("SELECT u FROM User u WHERE u.status =: status and u.name =: name") User findUserByUserStatusAndUserName (@Param ("status") Integer userStatus, @Param ("name") String userName); 

6.2. Anyanyelvi

A natív lekérdezés definíciója szempontjából nincs különbség abban, hogy miként adunk át egy paramétert a néven keresztül a lekérdezéshez a JPQL-hez képest - a @Param kommentár:

@Query (value = "SELECT * FROM Users u WHERE u.status =: status and u.name =: name", nativeQuery = true) User findUserByStatusAndNameNamedParamsNative (@Param ("status") Integer status, @Param ("name" Karakterlánc neve);

7. Gyűjtési paraméter

Vizsgáljuk meg azt az esetet, amikor a hol JPQL vagy SQL lekérdezésünk záradéka tartalmazza a BAN BEN (vagy NEM BENT) kulcsszó:

SELECT u FROM User u WHERE u.name IN: nevek

Ebben az esetben meghatározhatunk egy lekérdezési módszert, amelyre szükség van Gyűjtemény paraméterként:

@Query (érték = "SELECT u FROM User u WHERE u.name IN: names") Lista findUserByNameList (@Param ("nevek") Gyűjteménynevek);

Mivel a paraméter a Gyűjtemény, azzal együtt használható Lista, HashSetstb.

Ezután megmutatjuk, hogyan lehet módosítani az adatokat a @Módosítása annotáció.

8. Frissítse a lekérdezéseket a következővel: @ Módosító

Tudunk használja a @Lekérdezés annotáció az adatbázis állapotának módosításához a @ hozzáadásávalMódosítása annotáció az adattár módszerére.

8.1. JPQL

Az adatot módosító adattár módszer két különbséggel rendelkezik az válassza lekérdezés - megvan a @ Módosító annotáció és természetesen a JPQL lekérdezés használja frissítés ahelyett válassza:

@Modifying @Query ("update user u set u.status =: status where u.name =: name") int updateUserSetStatusForName (@Param ("status") Integer status, @Param ("name") String name); 

A visszatérési érték meghatározza, hogy hány sorban frissült a lekérdezés végrehajtása. Az indexelt és a megnevezett paraméterek egyaránt használhatók a frissítési lekérdezéseken belül.

8.2. Anyanyelvi

Az adatbázis állapotát natív lekérdezéssel is módosíthatjuk. Csak hozzá kell adnunk a @ Módosító kommentár:

@Modifying @Query (value = "update users u set u.status =? Where u.name =?", NativeQuery = true) int updateUserSetStatusForNameNative (Egész állapot, String név);

8.3. Betétek

A beszúrási művelet végrehajtásához mindkettőt alkalmazni kell @ Módosító és használjon natív lekérdezést, mivel az INSERT nem része a JPA felületének:

@Modify @Query (value = "insert into Users (name, age, email, status) values ​​(: name,: age,: email,: status)", nativeQuery = true) void insertUser (@Param ("név") Karakterlánc neve, @Param ("kor") Egész kor, @Param ("állapot") Egész állapot, @Param ("e-mail") Karakterlánc-e-mail);

9. Dinamikus lekérdezés

Gyakran előfordul, hogy olyan SQL-utasítások készítésére van szükség, amelyek olyan feltételeken vagy adatkészleteken alapulnak, amelyek értéke csak futás közben ismert. És ezekben az esetekben nem csak statikus lekérdezést használhatunk.

9.1. Példa egy dinamikus lekérdezésre

Képzeljünk el például egy olyan helyzetet, amikor ki kell választanunk az összes felhasználót, amelynek e-mail címe van MINT futás közben meghatározott készletből - email1, email2, …, emailn:

KIVÁLASZTÁS u felhasználótól u HOL u.email LIKE '% email1%' vagy u.email LIKE '% email2%' ... vagy u.email LIKE '% emailn%'

Mivel a halmaz dinamikusan épül fel, fordítási időben nem tudhatjuk, hogy hány MINT kiegészítendő záradékok.

Ebben az esetben, nem használhatjuk csak a @Lekérdezés kommentár, mivel nem tudunk statikus SQL utasítást megadni.

Ehelyett egy egyedi összetett adattár megvalósításával kibővíthetjük az alapot JpaRepository funkcionalitást, és saját logikát nyújtunk a dinamikus lekérdezés összeállításához Vessünk egy pillantást erre.

9.2. Egyéni adattárak és a JPA Criteria API

Szerencsénkre, A Spring lehetőséget nyújt az alaptár tárolására az egyedi töredék interfészek használatával. Ezután összekapcsolhatjuk őket, hogy összetett adattárat hozzunk létre.

Kezdjük egy egyedi töredék felület létrehozásával:

nyilvános felület UserRepositoryCustom {List findUserByEmails (E-mailek beállítása); }

És akkor megvalósítjuk:

public class UserRepositoryCustomImpl implementálja UserRepositoryCustom {@PersistenceContext private EntityManager entitásManager; @ Nyilvános lista felülírása findUserByEmails (E-mailek beállítása) {CriteriaBuilder cb = entitásManager.getCriteriaBuilder (); CriteriaQuery lekérdezés = cb.createQuery (Felhasználó.osztály); Gyökérfelhasználó = query.from (Felhasználó.osztály); Path emailPath = user.get ("email"); Lista predikátumok = new ArrayList (); for (String email: emails) {predicates.add (cb.like (emailPath, email)); } query.select (felhasználó) .where (cb.vagy (predicates.toArray (új predikátum [predicates.size ()]))); return entitásManager.createQuery (lekérdezés) .getResultList (); }}

Amint a fentiekből kiderült, dinamikus lekérdezésünk elkészítéséhez a JPA Criteria API-t használtuk fel.

Ezenkívül meg kell győződnünk arról, hogy a Impl postfix az osztály nevében. A tavasz a UserRepositoryCustom megvalósítás as UserRepositoryCustomImpl. Mivel a töredékek önmagukban nem tárolók, Spring erre a mechanizmusra támaszkodik a töredék megvalósításának megtalálásához.

9.3. A meglévő adattár kibővítése

Figyelje meg, hogy a 2. és a 7. szakasz közötti összes lekérdezési módszer a UserRepository.

Tehát most integráljuk a töredékünket az új felület kiterjesztésével a UserRepository:

nyilvános felület A UserRepository kiterjeszti a JpaRepository, a UserRepositoryCustom {// lekérdezési módszereket a 2. szakaszból - 7. szakasz}

9.4. A Tárház használata

Végül meghívhatjuk dinamikus lekérdezési módszerünket:

E-mailek beállítása = new HashSet (); // a készlet kitöltése tetszőleges számú elemmel userRepository.findUserByEmails (e-mailek); 

Sikeresen létrehoztunk egy összetett adattárat, és meghívtuk az egyéni módszerünket.

10. Következtetés

Ebben a cikkben a lekérdezések definiálásának számos módját ismertettük a Spring Data JPA repository módszerekben a @Lekérdezés annotáció.

Megtanultuk az egyéni lerakat megvalósítását és a dinamikus lekérdezés létrehozását is.

Mint mindig, a cikkben használt teljes kódpéldák elérhetők a GitHubon.