2013-01-08 142 views
6

我有3個表等:JPA查詢過連接表

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

AB是A和B之間

利用該一個轉換表,我的類有這兩個類中沒有組合物彼此。但我想知道,使用JPQL查詢,如果有任何記錄存在於我的元素AB表中的A表中。數字或布爾值是我需要的。

因爲AB是一個轉換表,所以沒有模型對象,我想知道是否可以在我的Repository對象中使用@Query來完成此操作。

+0

我不是沒有實體對象肯定JPQL。爲什麼不是SQL? – vels4j

+0

Sql可以輕鬆實現,但我想在我的項目中保持一致性(僅使用JPA)。但當然,如果沒有辦法做到這一點,我會選擇SQL – Neron

回答

3

我建議使用JPQL的Native query method intead(JPA也支持原生查詢)。讓我們假設表A是客戶,表B是產品,AB是銷售。以下是獲取客戶訂購產品清單的查詢。

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

更正:認爲你的意思是使用本機查詢(即SQL)RATHER THQL JPQL(你把「原生查詢JPQL」,而JPQL是JPA自己的查詢語言)。 – DataNucleus

+0

@DataNucleus謝謝。現在更新答案。 – vels4j

+0

工作。謝謝 – Neron

4

AB表必須在實體中建模,以便在JPQL中查詢。因此,您必須將此模型設爲 自己的實體類或您A和/或B實體中的關聯。

+0

看起來是這樣。無論如何感謝 – Neron

1

其實,對這種情況的回答比你想象的要簡單。使用正確的工具來完成正確的工作很簡單。 JPA並不是爲執行復雜的SQL查詢而設計的,這就是SQL的用途!所以你需要一種方法讓JPA訪問生產級的SQL查詢;

em.createNativeQuery 

所以在你的情況下,你想要做的就是訪問AB表只尋找id字段。檢索完查詢後,請帶上您的id字段並使用id字段查找Java對象。這是第二次搜索真實,但SQL標準微不足道。

我們假設您正在尋找一個基於B對象引用次數的A對象。假設您想要一個半複雜的(但是典型的)SQL查詢來根據B對象的數量並按降序對A型對象進行分組。這將是一個典型的熱門查詢,您可能需要按照項目要求來實施。

你的原生SQL查詢是這樣:

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

現在,你想要做的是告訴JPA期望的形式是JPA可以接受ID列表翻盤。您需要組合一個額外的JPA實體。永遠不會以JPA的正常方式使用它。但JPA需要一種方法將查詢的對象返回給您。您將爲此搜索查詢組合一個實體,

@Entity 
public class IdSearch { 

    @Id 
    @Column 
    Long id; 

    public Long getId() { 
      return id; 
    } 

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

} 

現在你實現一小段代碼將兩種技術結合在一起;

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

這消除了需要一個國際IdSearch表!

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

TOT肉眼是奇妙簡化的方式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(); 
    } 

乾杯,

佩裏

[email protected]