jarní Data JPA @Query

přehled

jarní Data poskytují mnoho způsobů, jak definovat dotaz, který můžeme spustit. Jedním z nich je anotace @Query.

v tomto tutoriálu si ukážeme, jak použít anotaci @Query v jarních datech JPA ke spuštění jpql i nativních dotazů SQL.

ukážeme také, Jak vytvořit dynamický dotaz, když anotace @Query nestačí.

další čtení:

odvozené metody dotazu v repozitářích JPA pro jarní Data

Prozkoumejte mechanismus odvození dotazu v JPA pro jarní Data.
Číst více →

Spring Data JPA @Úpravy Anotace

Vytvořit DML a DDL dotazy v Spring Data JPA tím, že kombinuje @Dotaz a @Úpravy anotací
Číst více →

Vyberte Dotaz

s cílem definovat SQL provést na Jaře úložiště Dat metoda, můžeme komentovat metoda s @Dotazu anotace — jeho hodnota atributu obsahuje JPQL nebo SQL spustit.

anotace @dotazu má přednost před pojmenovanými dotazy, které jsou anotovány pomocí @NamedQuery nebo definovány v orm.xml soubor.

To je dobrý přístup na místo dotazu definice těsně nad metoda uvnitř úložiště, spíše než uvnitř našeho modelu domény jako pojmenované dotazy. Úložiště je zodpovědné za vytrvalost, takže je to lepší místo pro uložení těchto definic.

2.1. Jpql

ve výchozím nastavení definice dotazu používá JPQL.

podívejme se na jednoduchou metodu úložiště, která vrací aktivní uživatelské entity z databáze:

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

2.2. Nativní

k definování našeho dotazu můžeme použít také nativní SQL. Vše, co musíme udělat, je nastavit hodnotu nativeQuery atribut do pravda a definovat nativní SQL dotaz na hodnotu atributu anotace:

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

Definovat Pořadí v Dotazu

můžeme předat další parametry typ Druh na Jaře Dat metoda prohlášení, že má @Dotazu anotace. Bude to přeloženo do pořadí podle klauzule, která bude předána do databáze.

3.1. Třídění pro smíšené parlamentní shromáždění, za Předpokladu, a Odvozené Metody

Pro metody jsme se dostat ven z krabice jako findAll(Druh) nebo ty, které jsou generovány pomocí analýzy metodou podpisů, můžeme použít pouze vlastnosti objektu definovat náš druh:

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

Teď si představte, že chceme třídit podle délky názvu, ubytování:

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

Když jsme se spustit výše uvedený kód, obdržíme výjimku:

org.springframework.datum.mapování.PropertyReferenceException: pro typ uživatele nebyla nalezena žádná délka(název) vlastnosti!

3.2. JPQL

Když používáme JPQL dotazu definice, pak na Jaře Data mohou zvládnout třídění bez problémů — vše, co musíme udělat, je přidat parametr metody typu Řazení:

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

můžeme zavolat tuto metodu a předat Druh parametru, který se bude, aby výsledek vlastnost název objektu Uživatele:

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

A protože jsme použili @Dotazu anotace, můžeme použít stejný způsob, jak získat seřazený seznam Uživatelů podle délky jejich jména:

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

je důležité, že budeme používat JpaSort.nebezpečné() pro vytvoření instance objektu řazení.

když používáme:

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

pak dostaneme přesně stejnou výjimku, jakou jsme viděli výše pro metodu findAll ().

když Spring Data zjistí nebezpečné pořadí řazení pro metodu, která používá anotaci @Query, jednoduše připojí klauzuli řazení k dotazu-přeskočí kontrolu, zda vlastnost, kterou chcete třídit, patří do modelu domény.

3.3. Nativní

když anotace @Query používá nativní SQL, pak není možné definovat druh.

pokud tak učiníme, dostaneme výjimku:

org.springframework.datum.jpa.úložiště.dotaz.InvalidJpaQueryMethodException: Nelze použít nativní dotazy s dynamickým třídění a/nebo stránkování

Jako výjimka říká, nějak není podporována pro nativní dotazy. Chybová zpráva nám dává náznak, že stránkování způsobí také výjimku.

Existuje však řešení, které umožňuje stránkování, a my to pokryjeme v další části.

stránkování

stránkování nám umožňuje vrátit pouze podmnožinu celého výsledku na stránku. To je užitečné například při procházení několika stránkami dat na webové stránce.

další výhodou stránkování je, že množství dat odeslaných ze serveru na klienta je minimalizováno. Odesláním menších kusů dat můžeme obecně vidět zlepšení výkonu.

4.1. JPQL

Pomocí stránkování v JPQL dotazu definice je jednoduché:

@Query(value = "SELECT u FROM User u ORDER BY id")Page<User> findAllUsersWithPagination(Pageable pageable);

můžeme projít PageRequest parametru na stránku data.

stránkování je také podporováno pro nativní dotazy, ale vyžaduje trochu další práce.

4.2. Nativní

můžeme povolit stránkování nativních dotazů deklarováním dalšího atributu countQuery.

Toto definuje SQL provést počítat počet řádků v celém výsledek:

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

4.3. Jarní Data JPA verze před 2.0.4

výše uvedené řešení pro nativní dotazy funguje dobře pro jarní Data JPA verze 2.0.4 a novější.

před touto verzí, když se pokusíme provést takový dotaz, dostaneme stejnou výjimku, jakou jsme popsali v předchozí části třídění.

můžeme překonat tím, že přidá další parametr pro stránkování uvnitř našeho dotazu:

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

Ve výše uvedeném příkladu, můžeme přidat „\n– #stránkované\n“ jako zástupný symbol pro parametr stránkování. To říká jarní Data JPA, jak analyzovat dotaz a vložit stránkovací parametr. Toto řešení funguje pro databázi H2.

jsme se zabývali tím, jak vytvořit jednoduché select dotazy přes JPQL a nativní SQL. Dále ukážeme, jak definovat další parametry.

Indexované parametry dotazu

existují dva možné způsoby, jak můžeme předat parametry metody našemu dotazu: indexované a pojmenované parametry.

v této části se budeme zabývat indexovanými parametry.

5.1. JPQL

pro indexované parametry v JPQL předají jarní Data parametry metody dotazu ve stejném pořadí, v jakém jsou uvedeny v deklaraci metody:

@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);

u výše uvedených dotazů bude parametr status method přiřazen parametru dotazu s indexem 1 a parametr name method bude přiřazen parametru dotazu s indexem 2.

5.2. Rodák

Indexované parametry pro nativní dotazy fungovat přesně stejným způsobem jako pro JPQL:

@Query( value = "SELECT * FROM Users u WHERE u.status = ?1", nativeQuery = true)User findUserByStatusNative(Integer status);

V další části ukážeme jiný přístup: předávání parametrů přes jméno.

pojmenované parametry

můžeme také předat parametry metody dotazu pomocí pojmenovaných parametrů. Definujeme je pomocí anotace @Param uvnitř deklarace metody úložiště.

každý parametr označený @Param musí mít řetězec hodnot odpovídající odpovídajícímu názvu parametru dotazu JPQL nebo SQL. Dotaz s pojmenovanými parametry je snáze čitelný a je méně náchylný k chybám v případě, že je třeba dotaz změnit.

6.1. JPQL

jak bylo uvedeno výše, používáme anotaci @Param v deklaraci metody pro porovnání parametrů definovaných názvem v JPQL s parametry z Deklarace metody:

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

Všimněte si, že ve výše uvedeném příkladu jsme definovali naše SQL dotazu a metoda parametry mají stejné názvy, ale to není nutné tak dlouho, dokud hodnota řetězce jsou stejné:

@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. Rodák

Pro nativní definici dotazu, není žádný rozdíl v tom, jak předat parametr přes název dotazu ve srovnání s JPQL — budeme používat @Param anotace:

@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. Parametr kolekce

uvažujme případ, kdy klauzule where našeho dotazu JPQL nebo SQL obsahuje klíčové slovo IN (nebo ne IN) :

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

V tomto případě, můžeme definovat dotaz, metoda, která má Sbírku jako parametr:

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

Jako parametr je soubor, může být použit s Seznam, HashSet, atd.

dále si ukážeme, jak upravit data pomocí anotace @Modifying.

Aktualizace Dotazů S @Úpravy

můžeme použít @Dotazu anotace změnit stav databáze také přidání @Úpravy anotace do úložiště metoda.

8.1. JPQL

úložiště metoda, která mění data má dva rozdíly v porovnání s zvolte dotaz — to má @Úpravy anotace a, samozřejmě, JPQL dotazu používá aktualizace vyberte místo:

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

návratová hodnota určuje, kolik řádků provedení dotazu aktualizovány. Indexované i pojmenované parametry lze použít v aktualizačních dotazech.

8.2. Nativní

stav databáze můžeme upravit také nativním dotazem. Stačí přidat anotaci @Modifying:

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

8.3. Vloží

K provedení operace insert, musíme použít @Modifikovat a použít native query, protože VLOŽKA není součástí JPA rozhraní:

@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);

Dynamické Query

Často setkáme potřebu budování SQL na základě podmínek, nebo soubory dat, jejichž hodnoty jsou známy jen v běhu. A v těchto případech nemůžeme použít jen statický dotaz.

9.1. Příklad Dynamické Dotazu

například si představme situaci, kdy potřebujeme vybrat všechny uživatele, jehož e-mail je JAKO jeden z množiny definované v runtime — email1, email2, …, emailn:

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

Protože je dynamicky postaven, nemůžeme vědět, v compile-time, kolik JAKO ustanovení, které chcete přidat.

v tomto případě nemůžeme použít anotaci @Query, protože nemůžeme poskytnout statický příkaz SQL.

namísto toho implementací vlastního kompozitního repozitáře můžeme rozšířit základní funkce JpaRepository a poskytnout vlastní logiku pro vytváření dynamického dotazu. Podívejme se, jak to udělat.

9.2. Vlastní Repozitáře a SPS Kritéria API

Naštěstí pro nás, na Jaře poskytuje způsob, jak pro rozšíření základního úložiště pomocí vlastní fragment rozhraní. Pak je můžeme propojit a vytvořit kompozitní úložiště.

začneme vytvořením vlastního rozhraní fragmentů:

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

a pak to provedeme:

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(); }}

jak je uvedeno výše, využili jsme API kritérií JPA k vytvoření našeho dynamického dotazu.

také se musíme ujistit, že Impl postfix do názvu třídy. Jaro bude hledat implementaci UserRepositoryCustom jako UserRepositoryCustomImpl. Protože fragmenty nejsou repozitáři samy o sobě, Spring spoléhá na tento mechanismus, aby našel implementaci fragmentu.

9.3. Rozšíření stávajícího úložiště

Všimněte si, že všechny metody dotazu od sekce 2 do sekce 7 jsou v UserRepository.

takže nyní integrujeme náš fragment rozšířením nového rozhraní v UserRepository:

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

9.4. Pomocí úložiště

a nakonec můžeme volat naši dynamickou metodu dotazu:

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

úspěšně jsme vytvořili kompozitní úložiště a nazvali naši vlastní metodu.

závěr

v tomto článku jsme se zabývali několika způsoby definování dotazů v metodách úložiště jarních dat JPA pomocí anotace @Query.

naučili jsme se také implementovat vlastní úložiště a vytvořit dynamický dotaz.

jako vždy jsou kompletní příklady kódu použité v tomto článku k dispozici na Githubu.

Napsat komentář

Vaše e-mailová adresa nebude zveřejněna.