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]
Ich bin nicht sicher JPQL ohne Entitätsobjekt. Warum nicht SQL? – vels4j
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