2013-01-08 12 views
6

mam 3 tabele jak:JPA zapytań w tabeli przyłączenia

A        AB      B 
-------------     ------------    --------------- 
a1        a1,b1     b1 

AB tabeli przejście pomiędzy A i B

Dzięki temu moi klasy nie ma skład w tych dwóch klas wzajemnie . Ale chcę wiedzieć, że z zapytaniem JPQL, jeśli istnieją jakieś rekordy dla mojego elementu z tabeli w tabeli AB. Wystarczy liczba lub wartość boolowska, której potrzebuję.

Ponieważ AB jest tabelą przejściową, nie ma dla niej obiektu modelu i chcę wiedzieć, czy mogę to zrobić za pomocą obiektu @Query w repozytorium.

+0

Nie jestem pewien JPQL bez obiektu podmiotu. dlaczego nie SQL? – vels4j

+0

Sql może to zrobić łatwo, ale chcę zachować spójność (używać tylko JPA) w moim projekcie. Ale oczywiście, jeśli nie ma sposobu, aby to zrobić, wybiorę SQL – Neron

Odpowiedz

3

Proponuję użyć Native query method intead z JPQL (JPA obsługuje również zapytanie Native). Załóżmy, że tabela A to Klient, a tabela B to Produkt, a AB to Sprzedaż. Oto zapytanie o listę produktów zamówionych przez klienta.

entityManager.createNativeQuery("SELECT PRODUCT_ID FROM 
            SALE WHERE CUSTOMER_ID = 'C_123'"); 
+0

: myślę, że masz na myśli użycie zapytania Native (tj. SQL) RATHER THAN JPQL (wstawiasz "zapytanie natywne w JPQL", podczas gdy JPQL jest własnym językiem zapytań JPA). – DataNucleus

+0

@DataNucleus thanks. zaktualizowano odpowiedź teraz. – vels4j

+0

To działało. dzięki – Neron

4

Tabela AB musi zostać zamodelowana w jednostce, której dotyczy zapytanie w JPQL. Musisz więc modelować to jako klasę własnej jednostki lub stowarzyszenie w twojej jednostce A i/lub B.

+0

wydaje się tak. Mimo to dziękuję za poprawkę – Neron

1

Właściwie odpowiedź na tę sytuację jest prostsza, niż mogłoby się wydawać. Jest to prosta sprawa użycia odpowiedniego narzędzia do właściwej pracy. JPA nie zostało zaprojektowane do implementacji skomplikowanych zapytań SQL, do czego służy SQL! Potrzebujesz więc sposobu, aby JPA uzyskało dostęp do kwerend SQL na poziomie produkcyjnym;

em.createNativeQuery 

W twoim przypadku, to co chcesz zrobić, to uzyskać dostęp do tabeli AB, szukając tylko pola id. Po pobraniu zapytania, weź pole id i wyszukaj obiekt Java, używając pola id. To drugie wyszukiwanie prawdziwe, ale trywialne według standardów SQL.

Załóżmy, że szukasz obiektu A w zależności od tego, ile razy obiekt B go odwołuje. Załóżmy, że potrzebujesz złożonej (ale typowej) kwerendy SQL do grupowania obiektów typu A na podstawie liczby obiektów B w kolejności malejącej. Byłoby to typowe zapytanie o popularność, które możesz chcieć wdrożyć zgodnie z wymaganiami projektu.

Zapytanie SQL rodzimy byłby jako takie:

select a_id as id from AB group by a_id order by count(*) desc; 

Teraz to, co chcesz zrobić, to powiedzieć JPA oczekiwać listę id na powrót w formie, że WZP może zaakceptować. Musisz utworzyć dodatkowy podmiot JPA. Tego, który nigdy nie będzie używany w normalnym trybie WZP. Ale JPA potrzebuje sposobu, aby odzyskać z powrotem poszukiwane przedmioty. Użytkownik utworzyłby jednostkę dla tego zapytania jako takiego;

@Entity 
public class IdSearch { 

    @Id 
    @Column 
    Long id; 

    public Long getId() { 
      return id; 
    } 

    public void setId(Long id) { 
      this.id = id; 
    } 

} 

Teraz zaimplementowałeś trochę kodu, aby połączyć dwie technologie;

@SuppressWarnings("unchecked") 
    public List<IdSearch> findMostPopularA() { 
      return em.createNativeQuery("select a_id as id from AB group by a_id 
      order by count(*) desc", IdSearch.class).getResultList(); 
    } 

To wszystko, co musisz zrobić, aby JPA mogło pomyślnie zakończyć Twoją kwerendę. Aby dostać się do obiektów A, wystarczyłoby odwołać się do swojej listy A przy użyciu tradycyjnego podejścia JPA;

List<IdSearch> list = producer.getMostPopularA(); 
Iterator<IdSearch> it = list.iterator(); 
while (it.hasNext()) { 
    IdSearch a = it.next(); 
    A object = em.find(A.class,a.getId()); 
    // your in business! 

Nadal nieco więcej udoskonalenia powyższego może uprościć rzeczy nieco dalej, biorąc pod uwagę wiele możliwości struktury projektu SQL.Nieco bardziej skomplikowane zapytanie SQL zapewni jeszcze bardziej bezpośredni interfejs JPA do rzeczywistych danych;

@SuppressWarnings("unchecked") 
    public List<A> findMostPopularA() { 
      return em.createNativeQuery("select * from A, AB 
      where A.id = AB.a_id 
      group by a_id 
      order by count(*) desc", A.class).getResultList(); 
    } 

W ten sposób usuwa się konieczność znalezienia tablicy wyników wyszukiwania id!

List<A> list = producer.getMostPopularA(); 
Iterator<A> it = list.iterator(); 
while (it.hasNext()) { 
    A a = it.next(); 
    // your in business! 

Co może nie być jasne tot gołym okiem jest cudownie uproszczony sposób JPA pozwala na wykorzystanie skomplikowanych struktur SQL wewnątrz interfejsu JPA. Wyobraź sobie, jeśli SQL w następujący sposób;

SELECT array_agg(players), player_teams 
FROM (
    SELECT DISTINCT t1.t1player AS players, t1.player_teams 
    FROM (
    SELECT 
     p.playerid AS t1id, 
     concat(p.playerid,':', p.playername, ' ') AS t1player, 
     array_agg(pl.teamid ORDER BY pl.teamid) AS player_teams 
    FROM player p 
    LEFT JOIN plays pl ON p.playerid = pl.playerid 
    GROUP BY p.playerid, p.playername 
) t1 
INNER JOIN (
    SELECT 
    p.playerid AS t2id, 
    array_agg(pl.teamid ORDER BY pl.teamid) AS player_teams 
    FROM player p 
    LEFT JOIN plays pl ON p.playerid = pl.playerid 
    GROUP BY p.playerid, p.playername 
) t2 ON t1.player_teams=t2.player_teams AND t1.t1id <> t2.t2id 
) innerQuery 
GROUP BY player_teams 

Chodzi o to, że z interfejsem createNativeQuery, nadal można odzyskać dokładnie dane szukasz prosto do żądanego obiektu dla łatwego dostępu Java.

@SuppressWarnings("unchecked") 
    public List<A> findMostPopularA() { 
      return em.createNativeQuery("SELECT array_agg(players), player_teams 
      FROM (
        SELECT DISTINCT t1.t1player AS players, t1.player_teams 
        FROM (
        SELECT 
         p.playerid AS t1id, 
         concat(p.playerid,':', p.playername, ' ') AS t1player, 
         array_agg(pl.teamid ORDER BY pl.teamid) AS player_teams 
        FROM player p 
        LEFT JOIN plays pl ON p.playerid = pl.playerid 
        GROUP BY p.playerid, p.playername 
       ) t1 
       INNER JOIN (
        SELECT 
        p.playerid AS t2id, 
        array_agg(pl.teamid ORDER BY pl.teamid) AS player_teams 
        FROM player p 
        LEFT JOIN plays pl ON p.playerid = pl.playerid 
        GROUP BY p.playerid, p.playername 
       ) t2 ON t1.player_teams=t2.player_teams AND t1.t1id <> t2.t2id 
       ) innerQuery 
       GROUP BY player_teams 
      ", A.class).getResultList(); 
    } 

Cheers,

Perry

[email protected]

Powiązane problemy