実際、この状況に対する答えは、あなたが思っているよりも簡単です。適切な仕事に適切なツールを使用するのは簡単なことです。JPA は、複雑な SQL クエリを実装するようには設計されていません。それが SQL の目的です。したがって、JPA を取得して実稼働レベルの SQL クエリにアクセスする方法が必要です。
em.createNativeQuery
したがって、あなたの場合、IDフィールドのみを探してABテーブルにアクセスする必要があります。クエリを取得したら、id フィールドを取得し、id フィールドを使用して Java オブジェクトを検索します。これは真の 2 番目の検索ですが、SQL 標準では些細なことです。
B オブジェクトが参照する回数に基づいて A オブジェクトを探しているとします。B オブジェクトの数に基づいて降順でタイプ A オブジェクトをグループ化する、やや複雑な (しかし典型的な) SQL クエリが必要だとします。これは、プロジェクトの要件に従って実装したい典型的な人気クエリです。
ネイティブ SQL クエリは次のようになります。
select a_id as id from AB group by a_id order by count(*) desc;
ここでやりたいことは、JPA が受け入れることができる形式で id リストが返されることを期待するように JPA に指示することです。追加の JPA エンティティをまとめる必要があります。JPA の通常の方法では決して使用されないもの。しかし、JPA には、照会されたオブジェクトを戻す方法が必要です。この検索クエリのエンティティをそのまままとめます。
@Entity
public class IdSearch {
@Id
@Column
Long id;
public Long getId() {
return id;
}
public void setId(Long id) {
this.id = id;
}
}
ここで、2 つのテクノロジを結合するためのコードを少し実装します。
@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();
}
以上で、JPA を取得してクエリを正常に完了させるために必要な作業はこれだけです。A オブジェクトを取得するには、従来の JPA アプローチを使用して A リストを相互参照するだけです。
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!
それでも、上記をもう少し改良することで、実際には SQL 設計構造の多くの機能を考慮して、物事をさらに単純化することができます。少し複雑な SQL クエリは、実際のデータへのさらに直接的な JPA インターフェイスになります。
@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();
}
これにより、interterm IdSearch テーブルが不要になります。
List<A> list = producer.getMostPopularA();
Iterator<A> it = list.iterator();
while ( it.hasNext() ) {
A a = it.next();
// your in business!
肉眼ではわかりにくいかもしれませんが、JPA では、JPA インターフェース内で複雑な SQL 構造を利用できるようにする方法が驚くほど単純化されています。次のような SQL を想像してみてください。
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
要点は、createNativeQuery インターフェイスを使用すると、探しているデータを正確に取得し、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();
}