2013-01-08 39 views
6

Tôi có 3 bảng như:JPA truy vấn trên một bảng tham gia

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

AB là một bảng chuyển tiếp giữa A và B

Với điều này, các lớp học của tôi không có phần trong vòng hai loại cổ phiếu này với nhau . Nhưng tôi muốn biết rằng, với một truy vấn JPQL, nếu bất kỳ hồ sơ tồn tại cho phần tử của tôi từ một bảng trong bảng AB. Chỉ số hoặc giá trị boolean là những gì tôi cần.

Vì AB là một bảng chuyển tiếp, không có đối tượng mô hình nào cho nó và tôi muốn biết liệu tôi có thể làm điều này với một @Query trong đối tượng Kho lưu trữ của tôi hay không.

+0

Tôi không chắc chắn JPQL mà không đối tượng thực thể. tại sao không phải SQL? – vels4j

+0

Sql có thể làm điều đó một cách dễ dàng nhưng tôi muốn bảo toàn tính nhất quán (chỉ sử dụng JPA) trong dự án của tôi. Nhưng tất nhiên nếu không có cách nào để làm điều đó, tôi sẽ chọn SQL – Neron

Trả lời

3

Tôi đề nghị sử dụng Native query method intead của JPQL (JPA cũng hỗ trợ truy vấn Gốc). Giả sử bảng A là Khách hàng và bảng B là Sản phẩm và AB là Bán hàng. Đây là truy vấn để nhận danh sách các sản phẩm được khách hàng đặt hàng.

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

chỉnh sửa: nghĩ rằng bạn có nghĩa là sử dụng một truy vấn Native (tức là SQL) RATHER THAN JPQL (bạn đặt "Native query in JPQL", trong khi JPQL là ngôn ngữ truy vấn của JPA). – DataNucleus

+0

@DataNucleus cảm ơn. cập nhật câu trả lời ngay bây giờ. – vels4j

+0

Đã hiệu quả. cảm ơn – Neron

4

bảng AB phải được lập mô hình trong thực thể được truy vấn trong JPQL. Vì vậy, bạn phải lập mô hình này là một lớp thực thể riêng hoặc một liên kết trong thực thể A và B của bạn.

+0

nó có vẻ như vậy. Thanks anyway – Neron

1

Thực ra, câu trả lời cho tình huống này đơn giản hơn bạn nghĩ. Đó là một vấn đề đơn giản khi sử dụng đúng công cụ cho đúng công việc. JPA không được thiết kế để thực hiện các truy vấn SQL phức tạp, đó là những gì SQL là dành cho! Vì vậy, bạn cần một cách để có được JPA truy cập truy vấn SQL cấp sản xuất;

em.createNativeQuery 

Vì vậy, trong trường hợp của bạn những gì bạn muốn làm là truy cập vào bảng AB chỉ tìm kiếm trường id. Khi bạn đã truy lục truy vấn của mình, hãy lấy trường id của bạn và tra cứu đối tượng Java bằng trường id. Đó là tìm kiếm thứ hai đúng, nhưng tầm thường theo tiêu chuẩn SQL.

Giả sử bạn đang tìm đối tượng A dựa trên số lần đối tượng B tham chiếu đến đối tượng đó. Giả sử bạn đang muốn một truy vấn SQL bán phức tạp (nhưng điển hình) để nhóm các đối tượng kiểu A dựa trên số lượng các đối tượng B và theo thứ tự giảm dần. Đây sẽ là một truy vấn phổ biến điển hình mà bạn có thể muốn thực hiện theo yêu cầu của dự án.

truy vấn SQL mẹ đẻ của bạn sẽ là như vậy:

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

Bây giờ những gì bạn muốn làm là nói với JPA để mong đợi danh sách id để trở lại trong một hình thức mà JPA có thể chấp nhận. Bạn cần đặt cùng một thực thể JPA bổ sung. Một trong đó sẽ không bao giờ được sử dụng trong thời trang bình thường của JPA. Nhưng JPA cần một cách để có được các đối tượng truy vấn lại cho bạn. Bạn sẽ đặt cùng một thực thể cho truy vấn tìm kiếm này như vậy;

@Entity 
public class IdSearch { 

    @Id 
    @Column 
    Long id; 

    public Long getId() { 
      return id; 
    } 

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

} 

Bây giờ bạn thực hiện một chút mã để đưa hai công nghệ lại với nhau;

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

Có, đó là tất cả những gì bạn phải làm để có được JPA để truy vấn của bạn hoàn tất thành công. Để có được đối tượng A của bạn, bạn chỉ cần tham chiếu chéo vào danh sách A của bạn bằng cách sử dụng phương pháp JPA truyền thống, như vậy;

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! 

Tuy nhiên, một chút tinh tế hơn ở trên có thể đơn giản hóa nhiều thứ hơn thực tế do nhiều khả năng của cấu trúc thiết kế SQL.Một truy vấn SQL phức tạp hơn một chút sẽ có giao diện JPA trực tiếp hơn tới dữ liệu thực tế của bạn;

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

Điều này sẽ loại bỏ nhu cầu bảng Id tìm kiếm liên công!

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

Điều không thể rõ ràng là mắt thường là cách đơn giản tuyệt vời JPA cho phép bạn sử dụng các cấu trúc SQL phức tạp bên trong giao diện JPA. Hãy tưởng tượng nếu bạn là một SQL như sau;

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 

Vấn đề là với giao diện createNativeQuery, bạn vẫn có thể truy xuất chính xác dữ liệu bạn đang tìm kiếm và thẳng vào đối tượng mong muốn để dễ dàng truy cập bằng 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(); 
    } 

Chúc mừng,

Perry

[email protected]

Các vấn đề liên quan