2013-01-08 9 views
6

Ich habe 3 Tabellen wie:JPA Query-über eine Join-Tabelle

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

AB eine Übergangstabelle zwischen A und B

Damit haben meine Klassen keine Zusammensetzung innerhalb dieser beiden Klassen miteinander . Aber ich möchte wissen, dass mit einer JPQL-Abfrage, ob Datensätze für mein Element aus einer Tabelle in AB-Tabelle vorhanden sind. Nur Nummer oder ein boolescher Wert ist was ich brauche.

Weil AB eine Übergangstabelle ist, gibt es kein Modellobjekt dafür und ich möchte wissen, ob ich dies mit einem @Query in meinem Repository-Objekt tun kann.

+0

Ich bin nicht sicher JPQL ohne Entitätsobjekt. Warum nicht SQL? – vels4j

+0

Sql kann das leicht tun, aber ich möchte Konsistenz (um nur JPA zu verwenden) in meinem Projekt beibehalten. Aber natürlich, wenn es keine Möglichkeit gibt, es zu tun, wähle ich SQL – Neron

Antwort

3

Ich empfehle, Native query method intead von JPQL zu verwenden (JPA unterstützt auch Native Abfrage). Nehmen wir an, Tabelle A ist Kunde und Tabelle B ist ein Produkt und AB ist ein Verkauf. Hier ist die Abfrage für die Liste der Produkte, die von einem Kunden bestellt werden.

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

Korrektur: Sie meinen, verwenden Sie eine Native Abfrage (d. H. SQL) RATHER als JPQL (Sie setzen "Native Abfrage in JPQL", während JPQL ist JPA eigene Abfragesprache). – DataNucleus

+0

@DataNucleus danke. aktualisierte Antwort jetzt. – vels4j

+0

Das hat funktioniert. Vielen Dank – Neron

4

Die AB-Tabelle muss in einer Entität modelliert sein, die in JPQL abgefragt werden soll. Sie müssen dies also als eine eigene Entitätsklasse oder eine Assoziation in Ihrer A- und/oder B-Entität modellieren.

+0

es scheint so. Danke trotzdem – Neron

1

Eigentlich ist die Antwort auf diese Situation einfacher als Sie vielleicht denken. Es ist eine einfache Sache, das richtige Werkzeug für den richtigen Job zu verwenden. JPA wurde nicht für die Implementierung komplizierter SQL-Abfragen entwickelt, dafür ist SQL gedacht! Sie benötigen also eine Möglichkeit, um JPA den Zugriff auf eine SQL-Abfrage auf Produktionsebene zu ermöglichen.

em.createNativeQuery 

Also in Ihrem Fall, was Sie tun möchten, ist die AB-Tabelle nur für das ID-Feld sucht zugreifen. Sobald Sie Ihre Abfrage abgerufen haben, nehmen Sie Ihr ID-Feld und suchen Sie das Java-Objekt mit dem ID-Feld. Es ist eine zweite Suche wahr, aber nach SQL-Standards trivial.

Angenommen, Sie suchen nach einem A-Objekt, basierend auf der Anzahl, wie oft ein B-Objekt darauf verweist. Angenommen, Sie möchten eine halbkomplizierte (aber typische) SQL-Abfrage, um Objekte vom Typ A basierend auf der Anzahl der B-Objekte in absteigender Reihenfolge zu gruppieren. Dies wäre eine typische Beliebtheitssuche, die Sie gemäß den Projektanforderungen implementieren möchten.

Ihre nativen SQL-Abfrage würde als solche sein:

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

Nun, was wollen Sie ist JPA tun sagen, die ID-Liste Comeback in einer Form zu erwarten, dass der JPA akzeptieren. Sie müssen eine zusätzliche JPA-Entität zusammenstellen. Eine, die niemals in der normalen Art von JPA verwendet wird. Aber JPA benötigt eine Möglichkeit, die abgefragten Objekte zurück zu bekommen. Sie würden eine Entität für diese Suchanfrage als solche zusammenstellen;

@Entity 
public class IdSearch { 

    @Id 
    @Column 
    Long id; 

    public Long getId() { 
      return id; 
    } 

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

} 

Jetzt implementieren Sie ein wenig Code, um die beiden Technologien zusammen zu bringen;

Dort müssen Sie nur JPA aufrufen, damit Ihre Abfrage erfolgreich abgeschlossen wird. Um an Ihre A-Objekte zu kommen, würden Sie einfach die Referenz in Ihre A-Liste einbeziehen, indem Sie den traditionellen JPA-Ansatz verwenden.

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! 

Noch ein wenig mehr Verfeinerung der oben kann ein bisschen weiter vereinfachen Dinge tatsächlich die viele viele Fähigkeiten der SQL Design-Struktur gegeben.Eine etwas kompliziertere SQL-Abfrage führt zu einer noch direkteren JPA-Schnittstelle zu Ihren eigentlichen Daten.

@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(); 
    } 

Damit entfällt die Notwendigkeit einer interm IdSearch-Tabelle!

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

Was nicht klar sein kann tot mit dem bloßen Auge die wunderbar vereinfacht JPA ist erlaubt Ihnen, Verwendung von komplizierten SQL-Strukturen innerhalb der JPA-Schnittstelle zu machen. Stellen Sie sich vor, wenn Sie eine SQL wie folgt;

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 

Der Punkt ist, dass mit createNativeQuery Schnittstelle, haben Sie immer genau die Daten abrufen können, die Sie suchen und direkt in das gewünschte Objekt für den einfachen Zugriff von 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]