2012-08-06 15 views
8

Tôi có hai bảng - một bảng chứa Địa chỉ và một bảng chứa Ảnh. Trường chung duy nhất giữa chúng là PersonID. Chúng được ánh xạ tới hai POJO Classes Address and Photo. Tôi đã có thể tìm nạp chi tiết trong các bảng này bằng cách tạo tiêu chí và thêm hạn chế trên các trường. Làm thế nào chúng ta nên viết một tham gia trên hai bảng. Có thể nhận được kết quả như hai đối tượng -Address và hình ảnh.Cách nối hai thực thể không liên quan bằng cách sử dụng JPA và Hibernate

Tôi muốn tham gia trái để tôi có thể nhận được hồ sơ của những người không có ảnh. Tôi đã đọc rằng điều này có thể chỉ sử dụng hql nhưng điều này có thể được thực hiện bằng cách sử dụng tiêu chí là tốt?

Trả lời

10

Bạn có thể dễ dàng ghi truy vấn HQL sẽ trả về kết quả là hai đối tượng sử dụng Theta Join (như Adrian đã lưu ý) . Dưới đây là ví dụ:

String queryText = "select address, photo from Address address, Photo photo where address.personID=photo.personId"; 
List<Object[]> rows = session.createQuery(queryText).list(); 

for (Object[] row: rows) { 
    System.out.println(" ------- "); 
    System.out.println("Address object: " + row[0]); 
    System.out.println("Photo object: " + row[1]); 
} 

Như bạn có thể thấy danh sách trả về truy vấn của mảng Object [] đại diện cho mỗi hàng được tìm nạp. Phần tử đầu tiên của mảng này sẽ chứa một phần tử obejct và thứ hai - một phần tử khác.

EDIT:

Trong trường hợp trái tham gia tôi nghĩ rằng bạn cần phải sử dụng bản địa truy vấn SQL (không HQL truy vấn). Dưới đây là cách bạn có thể thực hiện việc này:

String queryText = "select address.*, photo.* from ADDRESS address 
        left join PHOTO photo on (address.person_id=photo.person_id)"; 

List<Object[]> rows = sess.createSQLQuery(queryText) 
          .addEntity("address", Address.class) 
          .addEntity("photo", Photo.class) 
          .list(); 

Điều này sẽ hữu ích cho trường hợp của bạn.

+0

Cảm ơn ví dụ nhưng chúng ta có thể thực hiện một phép nối trái ... tôi đã thử sử dụng "Địa chỉ bên trái ảnh tham gia" nhưng lỗi sau xảy ra ... "bên ngoài hoặc tham gia đầy đủ phải được theo sau bởi biểu thức đường dẫn" – juan

+0

Được. Tôi đã chỉnh sửa câu trả lời của mình và thêm ví dụ để tham gia trái. Tôi nghĩ rằng điều này sẽ làm việc cho bạn. – dimas

+0

@dimas chúng ta có thể sử dụng hql ở bên trái tham gia – dom

0

gì bạn đang tìm kiếm là

  1. HQL
  2. Tham gia vào lĩnh vực mà bạn chưa mô phỏng như các mối quan hệ
  3. Left Tham

(Trong thời gian các câu hỏi lần đầu tiên được hỏi và câu trả lời này đã được đưa ra) Hibernate hỗ trợ Theta Join cho phép bạn thực hiện 1 & 2. Tuy nhiên, chỉ có tham gia bên trong là có sẵn cho phong cách tham gia theta.

Cá nhân tôi khuyên bạn nên lập mô hình các mối quan hệ phù hợp, vì vậy bạn chỉ cần 1 & 3 được hỗ trợ tốt trong HQL.

(Một câu trả lời thực sự cung cấp một bản cập nhật về tính năng Hibernate mới cung cấp tính năng như vậy, mà bạn chỉ có thể tham khảo)

+0

Tự hỏi tại sao nó lại bị bỏ phiếu. Câu trả lời là trong thực tế chính xác (ngay cả các cơ sở câu trả lời được chấp nhận về điều này) và tôi đã đưa ra ví dụ chỉ vì nó là tầm thường để tìm thấy trong được cung cấp thông tin quan trọng được cung cấp. Và yêu cầu tham gia bên trái được đưa ra sau –

+0

@Ismael Tôi sẽ nói lại nó một chút nhưng tôi không nghĩ rằng những gì tôi nói là không đầy đủ: Không có cách thích hợp bằng cách sử dụng HQL để đạt được những gì được yêu cầu bởi OP. Theta tham gia là gần nhất anh ta có thể nhận được nhưng vì nó không làm những gì anh ta những gì, tôi chỉ sẽ không bận tâm đưa ra ví dụ về nó. –

0

Tốt nhất là nên có một lớp chứa những lớp học bạn muốn tham gia để có tất cả chúng lại với nhau.

Nhưng nếu bạn đang tham gia các bảng này chỉ với một số mục đích không thường xuyên, bạn có thể sử dụng tiêu chí và tải dữ liệu theo cách thủ công từ mỗi bảng và đặt chúng lại với nhau. (và có, bạn có thể có dữ liệu của các bảng này một cách riêng biệt nếu cho Địa chỉ và ảnh có hai lớp và bảng riêng biệt)

+0

martin bạn có thể vui lòng xây dựng một chút về điều này. Làm thế nào để tạo một lớp cho kịch bản này? – underdog

+0

Tạo một lớp học với các thuộc tính bạn có trong tham gia của bạn. Lớp này sẽ được ràng buộc với một bảng cơ sở dữ liệu với tên giữ mối quan hệ giữa các thực thể của bạn. (Ở đây cho phép gọi chúng là bảng 'address_photo_rel'). Vì vậy, khi hibernate đang tạo các bảng cho các lớp của bạn, bảng kết nối này cũng được tạo ra. _Nếu bạn không làm điều đó, và vì bạn có một mối quan hệ giữa các thực thể của bạn (ở đây 'địa chỉ' và' ảnh'), hibernate cuối cùng sẽ tạo ra bảng đó, nhưng bạn không kiểm soát được điều đó, vì bạn không có một lớp cho nó._ –

3

Cuối cùng sau 12 năm đội Hibernate có implemented such a feature

Từ Hibernate docs:

Các mệnh đề FROM cũng có thể chứa mối quan hệ rõ ràng tham gia bằng cách sử dụng tham gia khóa.Các kết nối này có thể là kiểu nối bên trong hoặc bên trái.

List<Person> persons = entityManager.createQuery(
    "select distinct pr " + 
    "from Person pr " + 
    "join pr.phones ph " + 
    "where ph.type = :phoneType", Person.class) 
.setParameter("phoneType", PhoneType.MOBILE) 
.getResultList(); 


List<Person> persons = entityManager.createQuery(
    "select distinct pr " + 
    "from Person pr " + 
    "left join pr.phones ph " + 
    "where ph is null " + 
    " or ph.type = :phoneType", Person.class) 
.setParameter("phoneType", PhoneType.LAND_LINE) 
.getResultList(); 

Hoặc bạn có thể sử dụng WITHON từ khóa. Một nhận xét về những

Sự khác biệt quan trọng là trong SQL tạo ra các điều kiện của VỚI/ON khoản được thực hiện một phần của mệnh đề ON trong tạo SQL, như trái ngược với các truy vấn khác trong phần này trong đó các điều kiện HQL/JPQL được thực hiện một phần của mệnh đề WHERE trong câu lệnh SQL được tạo.

Ví dụ

List<Object[]> personsAndPhones = session.createQuery(
    "select pr.name, ph.number " + 
    "from Person pr " + 
    "left join pr.phones ph with ph.type = :phoneType ") 
.setParameter("phoneType", PhoneType.LAND_LINE) 
.list(); 

Tôi đang háo hức để thử các tính năng mới.

3

Như tôi đã giải thích trong this article, bạn có hai lựa chọn:

  1. Kể từ Hibernate 5.1, bạn có thể sử dụng ad-hoc joins cho các tổ chức liên quan.

    Tuple postViewCount = entityManager.createQuery(
        "select p as post, count(pv) as page_views " + 
        "from Post p " + 
        "left join PageView pv on p.slug = pv.slug " + 
        "where p.title = :title " + 
        "group by p", Tuple.class) 
    .setParameter("title", "High-Performance Java Persistence") 
    .getSingleResult(); 
    
  2. Trước Hibernate 5.1, bạn chỉ có thể sử dụng kiểu ghép kiểu theta. Tuy nhiên, một tham gia kiểu theta tương đương với một equijoin, do đó bạn chỉ có thể mô phỏng INNER JOINs không OUTER JOINs.

    List<Tuple> postViewCount = entityManager.createQuery(
        "select p as post, count(pv) as page_views " + 
        "from Post p, PageView pv " + 
        "where p.title = :title and " + 
        "  (p.slug = pv.slug) " + 
        "group by p", Tuple.class) 
    .setParameter("title", "Presentations") 
    .getResultList(); 
    

Để biết thêm chi tiết, hãy kiểm tra this article.

+0

Có cách nào khác cho phiên bản trước không. Tôi đang sử dụng hibernate-entitymanager-5.0.9 mang lại cho tôi "con đường mong đợi cho tham gia!" lỗi –

+0

Bạn có thể sử dụng tham gia kiểu theta. –