author-avatar
Dominik Martyniak
JAVA 5 minut

Dynamiczne Warunki w Zapytaniach JPQL - Parametryzacja w Akcji

W programowaniu baz danych często zachodzi potrzeba tworzenia zapytań, które dostosowują swoje warunki w zależności od różnych parametrów. W języku Java Persistence Query Language (JPQL) istnieje możliwość tworzenia takich dynamicznych zapytań. W tym wpisie przyjrzymy się, jak parametryzować zapytania JPQL w taki sposób, aby ich warunki zmieniały się w zależności od określonych warunków.


Potrzeba Dynamicznych Zapytań.

 

Parametryzacja zapytań w JPQL staje się nieodzowna w sytuacjach, gdy chcemy tworzyć zapytania, których warunki zależą od różnych czynników. Przykładowo, może to dotyczyć filtrowania wyników na podstawie różnych kryteriów wybranych przez użytkownika w interfejsie aplikacji. W takich przypadkach statyczne zapytania nie wystarczą, a potrzebujemy sposobu na dynamiczne dostosowywanie warunków zapytania.

Można skorzystać np. z rozwiązań takich jak Querydsl (przykład zastosowania znajduje się w tym wpisie) lub Hibernate - Criteria Queries. 

Przykład Zapytania z Dynamicznymi Warunkami

 

Załóżmy, że mamy bazę danych transakcji i chcemy stworzyć zapytanie JPQL, które pobierze transakcje spełniające określone kryteria. Kryteria te mogą obejmować datę transakcji, kwotę, typ transakcji itp. Poniżej znajduje się przykład zapytania JPQL, które uwzględnia dynamicznie zmieniające się warunki:

TEN PRZYKŁAD JEDYNIE ILUSTRUJE JAK TEGO NIE ROBIĆ !

@Repository
public interface SQLTransactionRepository extends JpaRepository<SQLTransaction, String> {

    @Query("SELECT t FROM SQLTransaction t WHERE t.date >= :dateFrom AND t.date <= :dateTo")
    List<Transaction> findByDateBetween(@Param("dateFrom") LocalDate dateFrom,
                                        @Param("dateTo") LocalDate dateTo);

    @Query("SELECT t FROM SQLTransaction t WHERE t.date >= :dateFrom")
    List<Transaction> findByDateGreaterThan(@Param("dateFrom") LocalDate dateFrom);

    @Query("SELECT t FROM SQLTransaction t WHERE t.date <= :dateTo")
    List<Transaction> findByDateLessThan(@Param("dateTo") LocalDate dateTo);

    @Query("SELECT t FROM SQLTransaction t ")
    List<Transaction> find();

}

 

I obłsuga tego potworka

 

    public List<SQLTransaction> find(TransactionSearchCriteria criteria) {
        if (criteria.getFromDate() != null && criteria.getToDate() != null) {
            return repository.findByDateBetween(criteria.getFromDate(), criteria.getToDate());
        }
        if (criteria.getFromDate() != null) {
            return repository.findByDateGreaterThan(criteria.getFromDate());
        }
        if (criteria.getToDate() != null) {
            return repository.findByDateLessThan(criteria.getToDate());
        }
        return repository.find();
    }

 

Jak można zauważyć w przykładzie obsługi dwóch parametrów dat, konieczne jest utworzenie aż czterech oddzielnych metod. Taka redundancja kodu nie tylko nie jest estetyczna, ale także utrudnia utrzymanie kodu. Idealnym rozwiązaniem jest zastosowanie mechanizmu warunkowego, który automatycznie dostosowuje zachowanie w zależności od dostępnych parametrów. W ten sposób kod staje się bardziej czytelny i łatwiejszy do utrzymania.



Dynamiczne parametryzowanie w JPQL 

 

Uproścmy troche nasze Query:

    @Query("SELECT t FROM SQLTransaction t " +
            "WHERE ((:dateFrom IS NOT NULL AND t.date >= :dateFrom) OR (:dateFrom IS NULL )) " +
            "AND ((:dateTo IS NOT NULL and t.date <= :dateTo) OR (:dateTo IS NULL ))")
    List<Transaction> findByDateBetween(@Param("dateFrom") LocalDate dateFrom,
                                        @Param("dateTo") LocalDate dateTo);

 

W powyższym kodzie dokonaliśmy znaczącej uproszczenia. Zamiast tworzyć cztery oddzielne metody obsługujące różne przypadki, stworzyliśmy jedno zapytanie, które elastycznie dostosowuje się do parametrów. Warunki sprawdzają, czy parametry dateFrom i dateTo są nullami. Jeżeli tak, to warunki zwracają wartość true, co pozwala na uwzględnienie wszystkich możliwych przypadków w jednym zapytaniu. To znacznie poprawia czytelność kodu i ułatwia jego utrzymanie.

 

Podsumowanie

 

Parametryzacja zapytań JPQL, z uwzględnieniem dynamicznych warunków, stanowi kluczowy aspekt komunikacji z bazami danych w aplikacjach Java. Ta istotna umiejętność pozwala na elastyczne dostosowywanie zapytań do zmieniających się wymagań, co jest kluczowe w efektywnym zarządzaniu danymi. Niemniej jednak, powyższe podejście, które dobrze sprawdza się w przypadku od dwóch do czterech parametrów, może okazać się mniej praktyczne w przypadku bardziej złożonych scenariuszy. W takich sytuacjach warto rozważyć zastosowanie narzędzi takich jak Querydsl lub Hibernate Criteria, które oferują bardziej zaawansowane możliwości budowy zapytań, co znacznie ułatwia pracę z większą ilością parametrów i bardziej skomplikowanymi warunkami. Ostatecznie, wybór narzędzi zależy od konkretnej sytuacji i potrzeb projektu.

3
[jpql, java, sql]

Więcej od Dominik Martyniak

Więcej artykułów