Jarné údaje JPA @Query

1. Prehľad

Spring Data poskytuje mnoho spôsobov, ako definovať dopyt, ktorý môžeme vykonať. Jedným z nich je @Dopyt anotácia.

V tejto príručke si ukážeme ako používať @Dopyt anotácia v Spring Data JPA na vykonávanie dotazov JPQL aj natívnych SQL.

Tiež si ukážeme, ako vytvoriť dynamický dotaz, keď @Dopyt anotácia nestačí.

2. Vyberte možnosť Dotaz

Aby sme mohli definovať SQL, ktoré sa má vykonať pre metódu úložiska Spring Data, môžeme anotovať metódu pomocou @Dopyt anotácia - jej hodnotu atribút obsahuje JPQL alebo SQL na vykonanie.

The @Dopyt anotácia má prednosť pred pomenovanými dotazmi, ktoré sú anotované pomocou @NamedQuery alebo definované v orm.xml spis.

Je to dobrý prístup k umiestneniu definície dotazu tesne nad metódu do úložiska, a nie do nášho modelu domény ako pomenované dotazy. Úložisko je zodpovedné za perzistenciu, takže je lepšie ukladať tieto definície.

2.1. JPQL

V predvolenom nastavení používa definícia dotazu JPQL.

Pozrime sa na jednoduchú metódu úložiska, ktorá sa vráti aktívna Používateľ subjekty z databázy:

@Query ("VYBRAT u OD ODUZIVA u WHERE u.status = 1") Collection findAllActiveUsers (); 

2.2. Nativní

Na definovanie nášho dotazu môžeme použiť aj natívne SQL. Všetko, čo musíme urobiť, je nastaviť hodnotu nativeQuery atribút pravda a definovať natívny SQL dotaz v hodnotu atribút anotácie:

@Query (hodnota = "VÝBER * OD POUŽÍVATEĽOV u WHERE u.status = 1", nativeQuery = true) Kolekcia findAllActiveUsersNative (); 

3. Definujte objednávku v dotaze

Môžeme odovzdať ďalší parameter typu Triediť k deklarácii metódy Spring Data, ktorá má @Dopyt anotácia. Bude preložené do jazyka ZORADIŤ PODĽA klauzula, ktorá sa dostane do databázy.

3.1. Triedenie pre poskytnuté a odvodené metódy JPA

Pre metódy, ktoré dostaneme z krabice ako napr findAll (zoradiť) alebo tie, ktoré sú generované podpismi metód analýzy, na definovanie nášho triedenia môžeme použiť iba vlastnosti objektu:

userRepository.findAll (nové triedenie (Sort.Direction.ASC, "meno")); 

Teraz si predstavte, že chceme triediť podľa dĺžky vlastnosti mena:

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

Po vykonaní vyššie uvedeného kódu dostaneme výnimku:

org.springframework.data.mapping.PropertyReferenceException: pre typ User sa nenašla nijaká vlastnosť LENGTH (name)!

3.2. JPQL

Keď na definíciu dotazu použijeme JPQL, potom Spring Data bez problémov zvládne triedenie - všetko, čo musíme urobiť, je pridať parameter metódy typu Triediť:

@Query (hodnota = "VYBERTE OD F Užívateľa u") Zoznam findAllUsers (zoradenie podľa zoradenia); 

Túto metódu môžeme nazvať a zložiť a Triediť parameter, ktorý zoradí výsledok podľa názov majetok Používateľ objekt:

userRepository.findAllUsers (nové triedenie ("meno"));

A pretože sme použili @Dopyt anotácie, rovnakou metódou môžeme získať zoradený zoznam Používatelia podľa dĺžky ich mien:

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

Je nevyhnutné, aby sme ich používali JpaSort.unsafe () vytvoriť Triediť inštancia objektu.

Keď používame:

nový Triediť („DĹŽKA (meno)“); 

potom dostaneme presne tú istú výnimku, ktorú sme videli vyššie pre findAll () metóda.

Keď Spring Data objaví nebezpečné Triediť objednávka metódy, ktorá využíva @Dopyt anotáciu, potom iba pripojí klauzulu sort k dotazu - preskočí kontrolu, či vlastnosť na triedenie patrí k modelu domény.

3.3. Nativní

Keď @Dopyt anotácia používa natívne SQL, potom nie je možné definovať a Triediť.

Ak tak urobíme, dostaneme výnimku:

org.springframework.data.jpa.repository.query.InvalidJpaQueryMethodException: Nie je možné použiť natívne dotazy s dynamickým radením a / alebo stránkovaním

Ako hovorí výnimka, zoradenie nie je podporované pre natívne dotazy. Chybové hlásenie nám naznačuje, že stránkovanie tiež spôsobí výnimku.

Existuje však riešenie, ktoré umožňuje stránkovanie, a venujeme sa mu v nasledujúcej časti.

4. Stránkovanie

Stránkovanie nám umožňuje vrátiť iba podmnožinu celého výsledku v a Strana. Je to užitočné napríklad pri navigácii cez niekoľko stránok s údajmi na webovej stránke.

Ďalšou výhodou stránkovania je, že je minimalizované množstvo dát odosielaných zo servera na klienta. Zasielaním menších údajov môžeme všeobecne vidieť zlepšenie výkonu.

4.1. JPQL

Použitie stránkovania v definícii dotazu JPQL je jednoduché:

@Query (hodnota = "VYBERTE OD F Užívateľa u OBJEDNAŤ ID") Stránka findAllUsersWithPagination (stránkovateľné stránkovateľné); 

Môžeme prejsť a PageRequest parameter na získanie stránky s údajmi.

Stránkovanie je podporované aj pre natívne dotazy, vyžaduje však trochu ďalšej práce.

4.2. Nativní

Môžeme povoliť stránkovanie pre natívne dotazy vyhlásením ďalšieho atribútu countQuery.

Toto definuje SQL, ktoré sa má vykonať, aby spočítalo počet riadkov v celom výsledku:

@Query (value = "SELECT * FROM Users ORDER BY id", countQuery = "SELECT count (*) FROM Users", nativeQuery = true) Stránka findAllUsersWithPagination (stránkovateľné pagable);

4.3. Jarné verzie JPA údajov pred 2.0.4

Vyššie uvedené riešenie pre natívne dotazy funguje dobre pre Spring Data JPA verzie 2.0.4 a novšie.

Pred touto verziou, keď sa pokúsime vykonať takýto dotaz, dostaneme rovnakú výnimku, ktorú sme opísali v predchádzajúcej časti o triedení.

Môžeme to prekonať pridaním ďalšieho parametra pre stránkovanie v našom dotaze:

@Query (value = "SELECT * FROM Users ORDER BY id \ n-- #pageable \ n", countQuery = "SELECT count (*) FROM Users", nativeQuery = true) Stránka findAllUsersWithPagination (pageable pageable);

V príklade vyššie pridáme „\ n– #pageable \ n“ ako zástupný znak pre parameter stránkovania. Toto hovorí spoločnosti Spring Data JPA, ako analyzovať dopyt a vložiť stránkovateľný parameter. Toto riešenie funguje pre H2 databázy.

Rozoberali sme, ako vytvárať jednoduché výberové dotazy prostredníctvom JPQL a natívneho SQL. Ďalej si ukážeme, ako definovať ďalšie parametre.

5. Indexované parametre dotazu

Existujú dva možné spôsoby, ako môžeme odovzdať parametre metódy do nášho dotazu: indexované a pomenované parametre.

V tejto časti sa budeme venovať indexovaným parametrom.

5.1. JPQL

Pre indexované parametre v JPQL bude Spring Data odovzdať parametre metódy do dotazu v rovnakom poradí, v akom sa vyskytujú v deklarácii metódy:

@Query ("VYBRAT u OD POUŽÍVATEĽA u WHERE u.status =? 1") Používateľ findUserByStatus (celé číslo); @Query ("VYBERTE OD FROM používateľa u WHERE u.status =? 1 a u.name =? 2") Používateľ findUserByStatusAndName (celé číslo, názov reťazca); 

Pre vyššie uvedené otázky: postavenie parameter metódy bude priradený parametru dotazu s indexom 1, a názov parameter metódy bude priradený parametru dotazu s indexom 2.

5.2. Nativní

Indexované parametre pre natívne dotazy fungujú presne rovnako ako pre JPQL:

@Query (value = "SELECT * FROM Users u WHERE u.status =? 1", nativeQuery = true) User findUserByStatusNative (celočíselný stav);

V nasledujúcej časti si ukážeme iný prístup: odovzdávanie parametrov pomocou názvu.

6. Pomenované parametre

Môžeme tiež odovzdať parametre metódy do dotazu pomocou pomenovaných parametrov. Definujeme ich pomocou @Param anotácia vo vnútri našej deklarácie metódy úložiska.

Každý parameter je anotovaný pomocou @Param musí mať hodnotový reťazec zodpovedajúci zodpovedajúcemu názvu parametra dotazu JPQL alebo SQL. Dotaz s pomenovanými parametrami je ľahšie čitateľný a je menej náchylný na chyby v prípade, že je potrebné dotaz refaktorovať.

6.1. JPQL

Ako už bolo spomenuté vyššie, používame @Param anotácia v deklarácii metódy, aby zodpovedala parametrom definovaným menom v JPQL s parametrami z deklarácie metódy:

@Query ("VYBERTE OD FROM Užívateľa u WHERE u.status =: status a u.name =: name") User findUserByStatusAndNameNamedParams (@Param ("status") Integer status, @Param ("name") Názov reťazca); 

Všimnite si, že vo vyššie uvedenom príklade sme definovali naše parametre dotazu a metódy SQL tak, aby mali rovnaké názvy, ale nie je to potrebné, pokiaľ sú hodnotové reťazce rovnaké:

@Query ("VYBERTE OD FROM Užívateľa u KDE u.status =: status a u.name =: name") User findUserByUserStatusAndUserName (@Param ("status") Celé číslo userStatus, @Param ("meno") reťazec userName); 

6.2. Nativní

Pre definíciu natívneho dotazu nie je žiadny rozdiel v tom, ako odovzdávame parameter cez meno do dotazu v porovnaní s JPQL - používame @Param anotácia:

@Query (value = "SELECT * FROM Users u WHERE u.status =: status and u.name =: name", nativeQuery = true) User findUserByStatusAndNameNamedParamsNative (@Param ("status") Integer status, @Param ("name") ) Názov reťazca);

7. Parameter zhromažďovania

Zvážme prípad, keď kde doložka nášho dotazu JPQL alebo SQL obsahuje IN (alebo NIE V) kľúčové slovo:

VYBERTE u OD POUŽÍVATEĽA u KDE u.name IN: mená

V tomto prípade môžeme definovať metódu dotazu, ktorá trvá Zbierka ako parameter:

@Query (hodnota = "VYBRAT u OD UŽÍVATEĽA u KDE u.name IN: mená") Zoznam findUserByNameList (@Param ("names") Názvy zbierok);

Pretože parameter je a Zbierka, dá sa použiť s Zoznam, HashSet, atď.

Ďalej si ukážeme, ako upraviť údaje pomocou znaku @Úpravy anotácia.

8. Aktualizujte dotazy pomocou @ Úpravy

Môžeme Použi @Dopyt anotácia na úpravu stavu databázy pridaním znaku @Úpravy anotácia na metódu úložiska.

8.1. JPQL

Metóda úložiska, ktorá upravuje údaje, má v porovnaní s metódou vyberte dopyt - má @ Úpravy anotácie a samozrejme používa dopyt JPQL aktualizovať namiesto vyberte:

@Modifying @Query ("update User u set u.status =: status where u.name =: name") int updateUserSetStatusForName (@Param ("status") Integer status, @Param ("name") Názov reťazca); 

Návratová hodnota definuje, koľko riadkov sa vykonanie dotazu aktualizovalo. V aktualizačných dotazoch je možné použiť indexované aj pomenované parametre.

8.2. Nativní

Stav databázy môžeme upraviť aj pomocou natívneho dotazu. Musíme len pridať @ Úpravy anotácia:

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

8.3. Vložky

Na vykonanie operácie vloženia musíme použiť obidve @ Úpravy a použite natívny dotaz, pretože INSERT nie je súčasťou rozhrania JPA:

@Modifying @Query (value = "vložte do hodnoty Users (meno, vek, e-mail, stav) (: name,: age,: email,: status)", nativeQuery = true) void insertUser (@Param ("name") Názov reťazca, @Param ("vek") Celé číslo, @Param ("stav") Stav celého čísla, @Param ("e-mail"), reťazec));

9. Dynamický dopyt

Často sa stretneme s potrebou budovania príkazov SQL na základe podmienok alebo súborov údajov, ktorých hodnoty sú známe iba za behu programu. A v týchto prípadoch nemôžeme použiť iba statický dotaz.

9.1. Príklad dynamického dopytu

Predstavme si napríklad situáciu, keď musíme vybrať všetkých používateľov, ktorých e-mail je PÁČI SA MI TO jeden zo sady definovanej za behu - email1, email2, …, emailn:

VYBERTE U OD POUŽÍVATEĽA u KDE u.email LIKE '% email1%' alebo u.email LIKE '% email2%' ... alebo u.email LIKE '% emailn%'

Pretože je množina dynamicky konštruovaná, nemôžeme vedieť, koľko ich je v čase kompilácie PÁČI SA MI TO doložky pridať.

V tomto prípade, nemôžeme len použiť @Dopyt anotáciu, pretože nemôžeme poskytnúť statický príkaz SQL.

Namiesto toho môžeme implementáciou vlastného zloženého úložiska rozšíriť základňu JpaRepository funkčnosť a poskytujeme vlastnú logiku pre zostavenie dynamického dotazu. Poďme sa pozrieť na to, ako to urobiť.

9.2. Custom Repositories and the JPA Criteria API

Našťastie pre nás, Jar poskytuje spôsob rozšírenia základného úložiska pomocou vlastných fragmentových rozhraní. Potom ich môžeme prepojiť a vytvoriť tak zložené úložisko.

Začneme vytvorením vlastného rozhrania fragmentu:

verejné rozhranie UserRepositoryCustom {List findUserByEmails (Set emails); }

A potom to implementujeme:

verejná trieda UserRepositoryCustomImpl implementuje UserRepositoryCustom {@PersistenceContext private EntityManager entityManager; @ Verejný zoznam Verejný zoznam findUserByEmails (nastavenie e-mailov) {CriteriaBuilder cb = entityManager.getCriteriaBuilder (); CriteriaQuery query = cb.createQuery (User.class); Root user = query.from (User.class); Cesta emailPath = user.get ("email"); Zoznam predikátov = nový ArrayList (); pre (String email: emails) {predicates.add (cb.like (emailPath, email)); } query.select (používateľ) .where (cb.or (predicates.toArray (nový Predicate [predicates.size ()])))); návrat entityManager.createQuery (dotaz) .getResultList (); }}

Ako je uvedené vyššie, na vytvorenie nášho dynamického dotazu sme použili rozhranie API JPA Criteria.

Musíme tiež zahrnúť Impl postfix v názve triedy. Jar bude prehľadávať UserRepositoryCustom implementácia ako UserRepositoryCustomImpl. Pretože fragmenty samy o sebe nie sú úložiskami, Spring sa pri hľadaní implementácie fragmentov spolieha na tento mechanizmus.

9.3. Rozšírenie existujúceho úložiska

Všimnite si, že všetky metódy dotazu od časti 2 do časti 7 sú v UserRepository.

Takže teraz integrujeme náš fragment rozšírením nového rozhrania do UserRepository:

verejné rozhranie UserRepository rozširuje JpaRepository, UserRepositoryCustom {// metódy dotazu z časti 2 - časť 7}

9.4. Používanie úložiska

A nakoniec môžeme zavolať našu metódu dynamického dotazu:

Nastaviť e-maily = nový HashSet (); // naplnenie sady ľubovoľným počtom položiek userRepository.findUserByEmails (e-maily); 

Úspešne sme vytvorili zložené úložisko a zavolali sme našu vlastnú metódu.

10. Záver

V tomto článku sme sa zaoberali niekoľkými spôsobmi definovania dotazov v metódach úložiska Spring Data JPA pomocou @Dopyt anotácia.

Naučili sme sa tiež, ako implementovať vlastné úložisko a vytvoriť dynamický dotaz.

Úplné príklady kódov použitých v tomto článku sú ako vždy k dispozícii na GitHub.


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