tavaszi adatok JPA @Query

áttekintés

a tavaszi adatok számos módot kínálnak a végrehajtható lekérdezés meghatározására. Ezek egyike a @Query annotáció.

ebben az oktatóanyagban bemutatjuk, hogyan kell használni a @ Query annotációt a Spring Data JPA-ban mind a jpql, mind a natív SQL lekérdezések végrehajtásához.

azt is megmutatjuk, hogyan lehet dinamikus lekérdezést készíteni, ha a @Query megjegyzés nem elegendő.

további információk:

származtatott lekérdezési módszerek a Spring Data JPA tárolókban

fedezze fel a lekérdezés származtatási mechanizmusát a Spring Data JPA-ban.
Olvass tovább →

Spring Data JPA @Modifying Annotation

hozzon létre DML és DDL lekérdezéseket a Spring Data JPA-ban a @Query és a @Modifying annotations
több →

Select Query

a Spring adattár metódus végrehajtásához szükséges SQL meghatározásához a @Query annotációval jegyzetelhetjük a módszert — az érték attribútuma tartalmazza a végrehajtandó JPQL-t vagy SQL-t.

a @Query annotáció elsőbbséget élvez az elnevezett lekérdezésekkel szemben, amelyek @NamedQuery-vel vannak jegyzetelve vagy orm-ben vannak definiálva.xml fájl.

jó megközelítés, ha a lekérdezésdefiníciót közvetlenül a metódus fölé helyezzük az adattárban, nem pedig a domain modellünkben, mint elnevezett lekérdezéseket. 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 definíciója JPQL-t használ.

nézzünk meg egy egyszerű adattárolási módszert, amely aktív felhasználói entitásokat ad vissza az adatbázisból:

@Query("SELECT u FROM User u WHERE u.status = 1")Collection<User> findAllActiveUsers();

2.2. Natív

a lekérdezés meghatározásához natív SQL-t is használhatunk. Csak annyit kell tennünk, hogy a nativeQuery attribútum értékét true értékre állítjuk, és meghatározzuk a natív SQL lekérdezést az annotáció value attribútumában:

@Query( value = "SELECT * FROM USERS u WHERE u.status = 1", nativeQuery = true)Collection<User> findAllActiveUsersNative();

határozzuk meg a sorrendet egy lekérdezésben

átadhatunk egy további típusú paramétert Rendezés egy tavaszi adat metódus deklarációhoz, amely @Query annotációval rendelkezik. Ez lesz lefordítva a ORDER BY záradék, hogy kerül át az adatbázisba.

3.1. A JPA által biztosított és származtatott módszerek rendezése

a dobozból kikerülő módszerekhez, például a Findall(rendezés) vagy a metódus aláírások elemzésével generált módszerekhez, csak az objektum tulajdonságait használhatjuk a rendezés meghatározásához:

userRepository.findAll(Sort.by(Sort.Direction.ASC, "name"));

most képzelje el, hogy egy név tulajdonság hossza szerint szeretnénk rendezni:

userRepository.findAll(Sort.by("LENGTH(name)"));

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

org.tavaszi keret.data.térképezés.PropertyReferenceException: nem található tulajdonság hossza(név) a type User számára!

3.2. JPQL

amikor a jpql-t használjuk a lekérdezés meghatározásához, akkor a tavaszi adatok probléma nélkül kezelhetik a rendezést — csak annyit kell tennünk, hogy hozzáadunk egy metódus paramétert Rendezés típus:

@Query(value = "SELECT u FROM User u")List<User> findAllUsers(Sort sort);

meghívhatjuk ezt a módszert, és átadhatunk egy rendezési paramétert, amely az eredményt a felhasználói objektum name tulajdonságával rendezi:

userRepository.findAllUsers(Sort.by("name"));

mivel a @Query annotációt használtuk, ugyanezt a módszert használhatjuk a felhasználók rendezett listájának lekérésére a nevük hossza szerint:

userRepository.findAllUsers(JpaSort.unsafe("LENGTH(name)"));

fontos, hogy a JpaSort-ot használjuk.nem biztonságos () rendezési objektum példány létrehozásához.

amikor használjuk:

Sort.by("LENGTH(name)");

akkor pontosan ugyanazt a kivételt kapjuk, mint fent láttuk a findAll() módszer esetében.

amikor a Spring Data felfedezi a @Query annotációt használó módszer nem biztonságos rendezési sorrendjét, akkor csak a rendezési záradékot fűzi a lekérdezéshez — kihagyja annak ellenőrzését, hogy a rendezendő tulajdonság a tartománymodellhez tartozik-e.

3.3. Natív

ha a @Query annotáció natív SQL-t használ, akkor nem lehet Sort meghatározni.

ha igen, kivételt kapunk:

org.tavaszi keret.data.jpa.adattár.lekérdezés.InvalidJpaQueryMethodException: nem használható natív lekérdezések dinamikus rendezéssel és/vagy lapozással

a kivétel szerint a rendezés nem támogatott natív lekérdezésekhez. A hibaüzenet arra utal, hogy a lapozás kivételt is okoz.

van azonban egy megoldás, amely lehetővé teszi az oldalszámozást, és ezt a következő szakaszban ismertetjük.

oldalszámozás

oldalszámozás lehetővé teszi számunkra, hogy az oldal teljes eredményének csak egy részhalmazát adjuk vissza. Ez akkor hasznos, ha például egy weboldalon több oldalnyi adatot navigál.

a lapozás másik előnye, hogy a szerverről az ügyfélre küldött adatok mennyisége minimális. Kisebb adatok kü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(value = "SELECT u FROM User u ORDER BY id")Page<User> findAllUsersWithPagination(Pageable pageable);

átadhatunk egy PageRequest paramétert, hogy egy oldalnyi adatot kapjunk.

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

4.2. Natív

engedélyezhetjük a natív lekérdezések lapozását egy további attribútum countQuery deklarálásával.

ez határozza meg a végrehajtandó SQL-t, hogy megszámolja a sorok számát az egész eredményben:

@Query( value = "SELECT * FROM Users ORDER BY id", countQuery = "SELECT count(*) FROM Users", nativeQuery = true)Page<User> findAllUsersWithPagination(Pageable pageable);

4.3. Spring Data JPA 2.0.4 előtti verziói

a fenti megoldás natív lekérdezésekhez jól működik a Spring Data JPA 2.0.4-es és újabb verziói esetén.

ezt a verziót megelőzően, amikor megpróbálunk végrehajtani egy ilyen lekérdezést, ugyanazt a kivételt kapjuk, amelyet az előző szakaszban a rendezésről írtunk le.

ezt leküzdhetjük egy további paraméter hozzáadásával a lapozáshoz a lekérdezésen belül:

@Query( value = "SELECT * FROM Users ORDER BY id \n-- #pageable\n", countQuery = "SELECT count(*) FROM Users", nativeQuery = true)Page<User> findAllUsersWithPagination(Pageable pageable);

a fenti példában a “\n– #pageable\n” értéket adjuk hozzá a lapozási paraméter helyőrzőjeként. 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 számára működik.

bemutattuk, hogyan lehet egyszerű select lekérdezéseket létrehozni JPQL és natív SQL segítségével. Ezután megmutatjuk, hogyan lehet további paramétereket meghatározni.

indexelt lekérdezési paraméterek

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

ebben a szakaszban az indexelt paramétereket tárgyaljuk.

5.1. JPQL

a jpql indexelt paramétereihez a tavaszi adatok a metódusparamétereket ugyanabban a sorrendben adják át a lekérdezésnek, mint a metódus deklarációban:

@Query("SELECT u FROM User u WHERE u.status = ?1")User findUserByStatus(Integer status);@Query("SELECT u FROM User u WHERE u.status = ?1 and u.name = ?2")User findUserByStatusAndName(Integer status, String name);

a fenti lekérdezések esetében a status method paraméter az 1.indexű lekérdezési paraméterhez, a name method paraméter pedig a 2. indexű lekérdezési paraméterhez lesz hozzárendelve.

5.2. Natív

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)User findUserByStatusNative(Integer status);

a következő részben más megközelítést mutatunk be: paraméterek átadása a név segítségével.

nevezett paraméterek

metódusparamétereket is átadhatunk a lekérdezésnek a megnevezett paraméterek használatával. Ezeket a @Param annotáció segítségével határozzuk meg a repository method deklarációnkban.

minden @Param jelöléssel ellátott paraméternek rendelkeznie kell egy értéklánccal, amely megfelel a megfelelő JPQL vagy SQL lekérdezési paraméter nevének. A megnevezett paraméterekkel rendelkező lekérdezések könnyebben olvashatók, és kevésbé hibásak, ha a lekérdezést újra kell írni.

6.1. JPQL

mint fentebb említettük, a @Param kommentárt használjuk a metódus deklarációban, hogy a jpql-ben név szerint meghatározott paramétereket a metódus deklaráció paramétereivel egyeztessük:

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

vegye figyelembe, hogy a fenti példában az SQL lekérdezésünket és metódusparamétereinket úgy határoztuk meg, hogy azonos nevűek legyenek, de ez nem kötelező mindaddig, 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. Natív

a natív lekérdezés definíciójához nincs különbség abban, hogy egy paramétert a név segítségével továbbítunk a lekérdezésnek a JPQL — hez képest-a @Param annotációt használjuk:

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

7. Gyűjteményparaméter

vizsgáljuk meg azt az esetet, amikor a jpql vagy SQL lekérdezés where záradéka tartalmazza az IN (vagy nem IN) kulcsszót:

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

ebben az esetben meghatározhatunk egy lekérdezési módszert, amely paraméterként veszi a gyűjteményt:

@Query(value = "SELECT u FROM User u WHERE u.name IN :names")List<User> findUserByNameList(@Param("names") Collection<String> names);

mivel a paraméter egy gyűjtemény, használható lista, HashSet stb.

ezután megmutatjuk, hogyan kell módosítani az adatokat a @ módosító kommentárral.

lekérdezések frissítése @Modifying

a @Query annotáció segítségével módosíthatjuk az adatbázis állapotát a @Modifying annotáció hozzáadásával a repository metódushoz.

8.1. JPQL

az adatokat módosító repository metódusnak két különbsége van a select lekérdezéshez képest — a @Modifying annotációval rendelkezik, és természetesen a jpql lekérdezés az update-et használja a select helyett:

@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 határozza meg, hogy hány sort a végrehajtás a lekérdezés frissítve. Mind az indexelt, mind a megnevezett paraméterek használhatók a frissítési lekérdezésekben.

8.2. Natív

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

@Modifying@Query(value = "update Users u set u.status = ? where u.name = ?", nativeQuery = true)int updateUserSetStatusForNameNative(Integer status, String name);

8.3. Beszúrások

beszúrási művelet végrehajtásához mind a @Modifying alkalmazást, mind a natív lekérdezést kell használnunk, mivel az INSERT nem része a JPA interfésznek:

@Modifying@Query( value = "insert into Users (name, age, email, status) values (:name, :age, :email, :status)", nativeQuery = true)void insertUser(@Param("name") String name, @Param("age") Integer age, @Param("status") Integer status, @Param("email") String email);

dinamikus lekérdezés

gyakran találkozunk azzal, hogy SQL utasításokat kell építeni olyan feltételek vagy adatkészletek alapján, amelyek értékei csak futásidőben ismertek. Ezekben az esetekben nem használhatunk statikus lekérdezést.

9.1. Példa dinamikus lekérdezésre

képzeljünk el például egy olyan helyzetet, amikor ki kell választanunk az összes felhasználót, akinek az e-mailje olyan, mint egy futásidőben meghatározott készletből-email1, email2,…, emailn:

SELECT u FROM User u WHERE u.email LIKE '%email1%' or u.email LIKE '%email2%' ... or u.email LIKE '%emailn%'

mivel a halmaz dinamikusan épül fel, fordításkor nem tudhatjuk, hogy hány hasonló záradékot kell hozzáadni.

ebben az esetben nem használhatjuk csak a @Query annotációt, mivel nem tudunk statikus SQL utasítást megadni.

ehelyett egy egyedi összetett adattár bevezetésével kibővíthetjük az alap JpaRepository funkciót, és saját logikát biztosíthatunk egy dinamikus lekérdezés felépítéséhez. Vessünk egy pillantást arra, hogyan kell ezt megtenni.

9.2. Egyéni tárolók és a JPA Criteria API

szerencsénkre a Spring lehetőséget nyújt az alaptár kiterjesztésére az egyéni töredék interfészek használatával. Ezután összekapcsolhatjuk őket egy összetett adattár létrehozásához.

kezdjük egy egyéni töredék felület létrehozásával:

public interface UserRepositoryCustom { List<User> findUserByEmails(Set<String> emails);}

aztán végrehajtjuk:

public class UserRepositoryCustomImpl implements UserRepositoryCustom { @PersistenceContext private EntityManager entityManager; @Override public List<User> findUserByEmails(Set<String> emails) { CriteriaBuilder cb = entityManager.getCriteriaBuilder(); CriteriaQuery<User> query = cb.createQuery(User.class); Root<User> user = query.from(User.class); Path<String> emailPath = user.get("email"); List<Predicate> predicates = new ArrayList<>(); for (String email : emails) { predicates.add(cb.like(emailPath, email)); } query.select(user) .where(cb.or(predicates.toArray(new Predicate))); return entityManager.createQuery(query) .getResultList(); }}

a fentiek szerint a JPA Criteria API-t használtuk a dinamikus lekérdezés felépítéséhez.

ezenkívül meg kell győződnünk arról, hogy az Impl postfix szerepel-e az osztály nevében. A Spring a UserRepositoryCustom implementációt fogja keresni UserRepositoryCustomImpl néven. 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 kiterjesztése

vegye figyelembe, hogy a 2.szakasztól a 7. szakaszig terjedő összes lekérdezési módszer a UserRepository-ban található.

tehát most integráljuk a töredéket az új felület kiterjesztésével a UserRepository-ban:

public interface UserRepository extends JpaRepository<User, Integer>, UserRepositoryCustom { // query methods from section 2 - section 7}

9.4. A Repository

használatával végül hívhatjuk dinamikus lekérdezési módszerünket:

Set<String> emails = new HashSet<>();// filling the set with any number of itemsuserRepository.findUserByEmails(emails);

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

következtetés

ebben a cikkben a Spring Data JPA repository metódusokban a lekérdezések meghatározásának számos módját tárgyaltuk a @Query annotáció használatával.

azt is megtanultuk, hogyan kell egyéni adattárat implementálni és dinamikus lekérdezést létrehozni.

mint mindig, a cikkben használt teljes kódpéldák elérhetők a GitHub-on.

Vélemény, hozzászólás?

Az e-mail-címet nem tesszük közzé.