Java JPA Criteria Query łączenie zapytań query

Java JPA Criteria Query łączenie zapytań query
S0
  • Rejestracja:ponad 4 lata
  • Ostatnio:20 dni
  • Postów:16
0

Cześć ukeiłem taką metodę jak poniżej, w metodzie tej wyszukuje sobie samochody, myślałem że z każdym ifem lista samochodów zostanie okrojona o warunek który postawiłem np brand=bmw, color=black, fuel=diesel miało zwracać czarne bmw w dieslu
a niestety zwraca wszystkie samochody w dieslu z bazy danych. Dzieje się to przez to że query nie jest "aktualizowane" tylko z każdym ifem jest nadpisywane i niestety nie potrafię tego przeskoczyć... :/

Kopiuj
@Override
    public List<Car> search(String brand, String model, String type, Integer registrationYear, String color,
                            String fuel, String transmission, String doors, boolean available){
 
        CriteriaBuilder cb=entityManager.getCriteriaBuilder();
        CriteriaQuery<Car> query=cb.createQuery(Car.class);
        Root<Car> car=query.from(Car.class);
        query.select(car);
        if(brand!=null){
            query.where(cb.equal(car.get("brand"), brand));
        }
        if(model!=null){
            query.where(cb.equal(car.get("model"), model));
        }
        if(type!=null){
            query.where(cb.equal(car.get("type"), type));
        }
        if(registrationYear !=null){
            query.where(cb.equal(car.get("registrationNumber"), registrationYear));
        }
        if(color!=null){
            query.where(cb.equal(car.get("color"), color));
        }
        if(fuel!=null){
            query.where(cb.equal(car.get("fuel"), Fuel.stringToFuelEnum(fuel)));
        }
        if(transmission!=null){
            query.where(cb.equal(car.get("transmission"), Transmission.stringToTransmissionEnum(transmission)));
        }
        if(doors!=null){
            query.where(cb.equal(car.get("doors"), doors));
        }
        TypedQuery<Car> query1=entityManager.createQuery(query);
        List<Car> s=query1.getResultList();
        return query1.getResultList();
    }

.andy
  • Rejestracja:ponad 16 lat
  • Ostatnio:około 3 lata
  • Postów:1524
0

Jak dla mnie to źle wygląda. W przypadku JPA możesz sobie albo zrobić metody w stylu findBy..., które automatycznie ci znajdą określone dane. Jednak przy wielu warunkach to bez sensu i wtedy lepiej dać @Query("SELECT y FROM zzz WHERE ooo") nad metodą.
W @Param dajesz parametry po jakich ma szukać.

Kopiuj
    @Query("SELECT c FROM Car c WHERE c.brand=?1 AND c.color>=?2 AND c.fuel=?3")
    List<Car> findByBrandAndColorAndFuel(@Param("brand") String brand, @Param("color") String color, @Param("fuel") String fuel);

Gdybyś chciał zrobić na wszystkie możliwe parametry, to nazywasz metodę np. findByAllParams. Metoda wtedy nie ma dwóch ekranów a zwraca to co chcesz, oczywiście musiałbyś do selekta dopisać pozostałe warunki ;)


Software is like sex: it's better when it's free.
- Linus Torvalds
edytowany 4x, ostatnio: .andy
S0
  • Rejestracja:ponad 4 lata
  • Ostatnio:20 dni
  • Postów:16
0

@.andy: chcę zrobić wyszukiwanie z możliwością zaznaczania i kombinowania wielu filtrów a napisać metody findBy z taką ilością możliwości kombinacji to hardcore, a co do drugiego sposobu jak tu zaimplementować kompilację parametrów? Bo chciałbym wyszukac np samochody w benzynie, albo samochody 3 drzwiowe z dieslu w kolorze czerwonym itp, zapytanie w tym wypadku zmienai się dynamicznie zależnie od tego co użytkownik zaznaczy na frontend

.andy
Dodałem kod wyżej dla trzech.
VD
  • Rejestracja:ponad 10 lat
  • Ostatnio:10 miesięcy
  • Postów:72
1

Bo tak jak w SQL powinno być jedno where, ale w nim może być kilka warunków łączonych np przez "and".
Przykład:

Kopiuj
Root<Pet> pet = cq.from(Pet.class);
cq.where(cb.equal(pet.get(Pet_.name), "Fido")
    .and(cb.equal(pet.get(Pet_.color), "brown");
Charles_Ray
  • Rejestracja:około 17 lat
  • Ostatnio:dzień
  • Postów:1875
0

Nie powinno być po prostu

Kopiuj
query = query.where(…);

?


”Engineering is easy. People are hard.” Bill Coughran
S0
  • Rejestracja:ponad 4 lata
  • Ostatnio:20 dni
  • Postów:16
0

@Charles_Ray: tak też próbuję że w każdym ifie dodaje nowe predicate a na końcu po prostu wykonuje query.where(brandPredicate, modelPredicate) niestety generowało to taki błąd że gdy nie podałem np modelu to wyskakiwał bład: predicate null expresion obszedłem go tak że na początku inicjuje wszystkie predicate i wykonują one zapytanie czy id samochodu jest wieksze od 0. Metoda chałpnicza lecz działa

Kopiuj
@Override
    public List<Car> search(String brand, String model, String type, Integer registrationYear, String color,
                            String fuel, String transmission, String doors, boolean available){
        int var=0;
        CriteriaBuilder cb=entityManager.getCriteriaBuilder();
        CriteriaQuery<Car> query=cb.createQuery(Car.class);
        Root<Car> car=query.from(Car.class);
        query.select(car);
        Predicate brandPredicate=cb.greaterThan(car.get("id"), var);
        Predicate modelPredicate=cb.greaterThan(car.get("id"), var);
        Predicate typePredicate=null;  //TUTAJ MUSZE ZROBIĆ TO CO U GÓRY
        Predicate registrationNumberPredicate=null;
        Predicate colorPredicate=null;
        Predicate fuelPredicate=null;
        Predicate transmissionPredicate=null;
        Predicate doorsPredicate=null;
        Predicate availablePredicate =null;;

        if(brand!=null){
            brandPredicate= cb.equal(car.get("brand"), brand);
        }
        if(model!=null){
            modelPredicate= cb.equal(car.get("model"), model);
        }
        if(type!=null){
            query.where(cb.equal(car.get("type"), type));
        }
        if(registrationYear !=null){
            query.where(cb.equal(car.get("registrationNumber"), registrationYear));
        }
        if(color!=null){
            query.where(cb.equal(car.get("color"), color));
        }
        if(fuel!=null){
            query.where(cb.equal(car.get("fuel"), Fuel.stringToFuelEnum(fuel)));
        }
        if(transmission!=null){
            query.where(cb.equal(car.get("transmission"), Transmission.stringToTransmissionEnum(transmission)));
        }
        if(doors!=null){
            query.where(cb.equal(car.get("doors"), doors));
        }
        query.where(brandPredicate, modelPredicate);

        return entityManager.createQuery(query).getResultList();
    }
.andy
  • Rejestracja:ponad 16 lat
  • Ostatnio:około 3 lata
  • Postów:1524
0

Software is like sex: it's better when it's free.
- Linus Torvalds
Charles_Ray
To jest level abstrakcji, OP ma bardziej podstawowy problem ze sklejeniem where :)
.andy
No to niech się podłączyć do bazy i zrobi zwykłego selekta najpierw.
Charles_Ray
  • Rejestracja:około 17 lat
  • Ostatnio:dzień
  • Postów:1875
0

Na logikę, to brakuje Ci jakiegoś OR/AND, wołanie kilka razy where spowoduje prawdopodobnie nadpisanie warunku. Najpierw zbuduj warunek, a na końcu query.where(zlozony_warunek).

Tu masz pokazane jak łączyć warunki: https://www.baeldung.com/jpa-and-or-criteria-predicates


”Engineering is easy. People are hard.” Bill Coughran
MrMadMatt
  • Rejestracja:ponad 9 lat
  • Ostatnio:17 dni
  • Postów:373
1

A musisz to robić w JPA? Jak ja byłem dawno temu juniorem i miałem taki case to używałem JDBC i sklejałem stringa z zapytaniem. (nie oceniajcie :D). Coś w tym stylu:

Kopiuj
String mySql = select * from cars where 1=1;

if(Objects.nonNull(type)) {
    mySql += "and type = :type";
}

I te ify ubierz sobie w jakąś strategię czy coś. Aby iterować po opcjach a nie kodzić je na chama.

Edit:
Pamiętam że parametr dla metody where w JPA też tak sklejałem jakimś andem jak tego SQLa. Ale za cholerę sobie nie przypomnę jak to wyglądało. Na pewno się da.

edytowany 1x, ostatnio: MrMadMatt
.andy
Wrzucałem wyżej jak to można ogarnąć. Na końcu sprowadza się to do czegoś takiego customerRepository.findAll(where(customerHasBirthday()).and(isLongTermCustomer()))
Charles_Ray
Klejenie SQL-a risky pomysł :)
RequiredNickname
Sklejasz SQL'a stringiem a potem SQL injection :)
JD
  • Rejestracja:około 19 lat
  • Ostatnio:około 8 godzin
0

a queryDsl?

RequiredNickname
  • Rejestracja:prawie 5 lat
  • Ostatnio:około 2 godziny
  • Postów:620
0
edytowany 1x, ostatnio: RequiredNickname

Zarejestruj się i dołącz do największej społeczności programistów w Polsce.

Otrzymaj wsparcie, dziel się wiedzą i rozwijaj swoje umiejętności z najlepszymi.