Wpis z mikrobloga

Mirki, programuję aplikację i mam pewien problem. Mam kilka modeli i odpowiadające im tabele w bazie danych, w uproszczeniu: Performance(id, name), Show(id, date, performanceid), Ticket(showid, sold). Potrzebuję otrzymać wynik o top n performances, np. (performance_id, liczba sprzedanych biletów) + przefiltrować niektóre wyniki (name, date etc.).
Samo zapytanie wiem jak wykonać, ale nie wiem zaprojektować klasy etc. Napisać metodę w PerformanceRepository typu getTop i zwracać... no właśnie co zwracać? Napisać dodatkową klasę (nie model) PerformanceWithNumberOfSoldTickets i zwracać listę obiektów tejże klasy? Czy może dodać podobny model bez tabeli w bazie danych i znowu zwracać listę?
#programowanie #java #spring
  • 14
to chyba najprosciej zdefiniowac sobie named queries na encji takie jakie potrzebujesz (czyli jpql czy hql) a potemi na transakcyjnym serwisie wywolywac dao wołające takie query, z ewentualnym dodaniem parametrów np maxResults.
@cage20: Czyli na encji dodać metodę numSoldTickets? Najpierw dostaję listę n performances z PerformanceRepository, a później w pętli wywołuję numSoldTickets? Jeśli tak, to za każdym razem muszę przekazywać kryteria (np. date) do numSoldTickets jak i do getTop z PerformanceRepository.
Klasa Performance:

@Entity
@NamedQueries({
@NamedQuery(name = Performance.TOPPERFORMANCE, query = "from Performance p order by size(p.tickets))})

@OneToMany
private List> tickets;
...

Service:

@Transactional
public List getTopPerformances(){
return dao.getTopPerformances();
}

DAO: (extends JpaRepository)

@Query(Performance.TOP
PERFORMANCE)
public List getTopPerformances(){
...
}

To taki najprostszy szkielet, w namedqueries mozesz podac parametry (np date albo ile rekordow ma wyciagac) a potem podstawisz te parametry w dao.
@cage20: Dzięki, ale nadal nie mam dla konkretnego performance liczby biletów, które spełniają pewne kryteria. Dla konkretnego performance istnieje wiele shows z daną datą, a każde konkretne show ma wiele biletów. Muszę dostać np. top 10 performances w ostatnim miesiącu (po liczbie sprzedanych biletów).
No to musisz sobie jakies proste zapytanko zrobić. Nie znam modelu i nie wiem jakie sa relacje, ale zakładam że są dwustronne i performance ma kolekcje shows, a show ma kolekcje biletow, to np cos takiego:
"select s.performance.name ,s.name ,s.date from Show s where s.date = :jakasData order by size(s.tickets)"
a potem to sobie mapujesz resulttransformerem na jakis obiekt widokowy czy cos,
@cage20: No właśnie co zwracać z DAO? Query powinno wyglądać mniej więcej tak:
SELECT p.id, count(p.id) AS total FROM performance p JOIN show s ON s.performanceid = p.id JOIN ticket t ON t.showid = s.id WHERE s.date BETWEEN ?1 AND ?2 AND t.category = ?3 GROUP BY p.id, ORDER BY count(p.id) DESC
@patste: zapytanie, które masz wywołaj z entityManagera.
|
Query q= entityManager.createNativeQuery("twoj sql");
q.getResultList(); // zwróci Ci listę tablic obiektów czyli List
Przeiteruj sobie tą listę i przypisz do obiektów przekazywnych do widoku

for(Object[] o: lista){
MojObiekt obj = new MojObiekt();
obj.setId(o[0]);
obj.setValue(o[1]);
}
@patste: Ok, przerobiłeś czystego SQL'a na CriteriaApi.
Bardzo dobre rozwiązanie w przypadku, gdy do zapytania czasami przekazujesz, a czasami nie, różne parametry. Rozwiązanie na pierwszy rzut oka wydaje się skomplikowane, ale daje bardzo dużą elastyczność.

Stałe zapytania, do których zawsze wstawiasz parametry dobrze jest robić w NamedQuery, bo te zapytanie jest transformowane na SQL w momencie kompilacji projektu i jest po prostu szybsze. ( ͡° ͜ʖ ͡°)