• Najnowsze pytania
  • Bez odpowiedzi
  • Zadaj pytanie
  • Kategorie
  • Tagi
  • Zdobyte punkty
  • Ekipa ninja
  • IRC
  • FAQ
  • Regulamin
  • Książki warte uwagi

Spring Specification - czy można dodać własne zapytanie

Aruba Cloud PRO i VPS, Openstack, VMWare, MS Hyper-V
+1 głos
123 wizyt
pytanie zadane 7 listopada 2022 w Java przez Lulex Użytkownik (820 p.)

Cześć,

stworzyłem w bazie danych metodę której użyłem do swotrzenia custom query w repozytorium:

@Query(value = "SELECT * FROM SHAPES WHERE COUNT_AREA(TYPE, RADIUS, WIDTH, HEIGHT) >= ?1", nativeQuery = true)
   List<ShapeEntity> getWithAreaGreaterThan(double area);

Walczę również ze specyfikacjami, aby dane można było wygodnie i szybko filtrować. 

Jednak mam problem z polem. "COUNT_AREA" to funkcja w bazie danych. Czy mogę w jakiś sposób użyć tego do specyfikacji? Nie mogę nic wygooglować na ten temat i obawiam się, że nie będzie to możliwe, ponieważ Specyfikacja operuje na polach klasy, które robię bez problemu:

public static Specification<ShapeEntity> radiusGreaterThan(Double radiusFrom) {
        return (root, query, builder) ->
                radiusFrom == null ?
                        builder.conjunction() :
                        builder.greaterThan(root.get("shapes").get("radius"), radiusFrom);
    }

Więc pytanie czy będzie to w ogóle możliwe czy raczej powinienem zrobić to dynamiczne wyszukiwanie w zupełnie inny sposób?

1 odpowiedź

+2 głosów
odpowiedź 8 listopada 2022 przez Wiciorny Ekspert (259,870 p.)

Zacznijmy od jednej istotnej rzeczy.
Interfejs Specyfication służy do określania predykatów w warunkach filtrowania.
Zapytanie z funkcja obliczającą- nie jest częścią warunków "spełnienia filtrowania, wyboru elementów" a jedynie jeje rezultat jako np  operacja sumująca już "wybrane parametry" w tym wypadku funkcja  powinna działać w ramach twojego predykatu i tam byc zdefiniowana.
Natomiast rezultat  wynikowy zapytania  będzie efektem końcowym jedynie. Coś na zasadzie : terminated operation.

Wszystko zależy jak zapisywane są dane dla tego pola w bazie? Czy jest to czysta funkcja, czy jej wynik, jednocześnie powinieneś mieć obiekt który poprzez ORM reprezentuje to w bazie danych.

Być może dobrym rozwiązaniem będzie utworzenie 1 z predykatów jako funkcje - tzw. wyrażenie lambda. które będzie ewaluowane podczas uruchomienia specyfikacji 
dla przykładu 
 

Predicate<Integer>  countAreaFn = (param1,param2,param3), -> ( result); 

jako RESULT -> możesz albo dowolnie podać referencje do funkcji jakiejś która na rzecz tego ma być wykonana, albo po prostu jesli np. byłoby to mnożenie, zsumować określone parametry. 

komentarz 19 listopada 2022 przez Lulex Użytkownik (820 p.)

Zawsze doceniam Twoją pomoc i wskazówki, ponieważ zazwyczaj udawało mi się rozwiązywać problem :D .

 

W tym przypadku jest nieco inaczej, ponieważ mam problem ze zrozumieniem i ułożeniem tego aby to jakkolwiek wyglądało, nie mogę też znaleźć jakiegoś odpowiedniego przykładu, wszędzie gdzie byłem są tylko te "proste" przypadki.

Predicate wygląda jak coś co chciałbym zastosować, tylko no właśnie jak to zrobić.

Nie ogarniam co się dzieje w twoim kodzie i jak to wykorzystać. Próbowałem iść w tym kierunku, czyli zależnie od kolumny, policzyć pole figury:

public static Specification<ShapeEntity> areaTo(double areaTo) {
        return (root, query, criteriaBuilder) -> {
            double area;
            switch (root.get("type").toString()) {
                case "CIRCLE":
                    area = Math.pow(Double.parseDouble(root.get("radius").toString()), 2) * Math.PI;
                    break;
                case "RECTANGLE":
                    area = Double.parseDouble(root.get("width").toString()) * Double.parseDouble(root.get("height").toString());
                    break;
                case "SQUARE":
                    area = Math.pow(Double.parseDouble(root.get("width").toString()), 2);
                    break;
                default:
                    throw new IllegalArgumentException();
            }
            return criteriaBuilder.lessThanOrEqualTo(????, areaTo);
        };
    }

jednak kompletnie nie wiem jak to wykorzystać i wrzucić w return.

Podobne pytania

0 głosów
1 odpowiedź 394 wizyt
pytanie zadane 19 maja 2017 w Java przez K0XM4N Gaduła (3,640 p.)
0 głosów
1 odpowiedź 234 wizyt
pytanie zadane 4 maja 2020 w Java przez scrxts Nowicjusz (150 p.)
0 głosów
0 odpowiedzi 242 wizyt
pytanie zadane 18 marca 2020 w Java przez Krab789 Nowicjusz (170 p.)

91,824 zapytań

140,490 odpowiedzi

316,950 komentarzy

61,159 pasjonatów

Motyw:

Akcja Pajacyk

Pajacyk od wielu lat dożywia dzieci. Pomóż klikając w zielony brzuszek na stronie. Dziękujemy! ♡

Oto dwie polecane książki warte uwagi. Pełną listę znajdziesz tutaj.

...