2011-08-24 25 views
5

Vấn đề là tôi có hai túi trong thực thể của mình mà tôi muốn hiển thị trong giao diện jsf của tôi (Mùa xuân ở phía sau để không tải xuống). Vì vậy, tôi phải háo hức lấy chúng để hiển thị các thông tin trong một danh sách như thế này:Hibernate fetch join -> không thể tìm nạp nhiều túi

  • điểm 1 (Label 1, Label 2) (Tag1 ... Tag n)
  • điểm 2 (Label 3, Label 4) (Tag1 ... Thẻ n)

Đặt cả hai danh sách vào trạng thái mong muốn không hoạt động. Vì vậy, tôi đã thử vận ​​may của mình bằng cách tìm nạp. Nó cho phép tôi lấy một danh sách, nhưng khi tôi thêm vào danh sách thứ hai tôi nhận được lỗi "không thể tìm nạp nhiều túi" đã biết.

Hibernate có thể xử lý hai lần tìm nạp trong một truy vấn không?

public class PointOfInterest 
@OneToMany(mappedBy="poi") 
private List<PointOfInterestLabel> labels = new ArrayList<PointOfInterestLabel>(); 

@ManyToMany 
private List<Tag> tags = new ArrayList<Tag>(); 

tôi lấy tham gia:

SELECT DISTINCT p from PointOfInterest p 
     left join fetch p.labels 
     left join fetch p.tags WHERE p.figure = :figure 

On khởi động việc tạo ra các nhà máy ngủ đông của tôi không thành công với:

Caused by: org.hibernate.loader.MultipleBagFetchException: cannot simultaneously fetch multiple bags 
    at org.hibernate.loader.BasicLoader.postInstantiate(BasicLoader.java:94) 
    at org.hibernate.loader.hql.QueryLoader.<init>(QueryLoader.java:123) 
    at org.hibernate.hql.ast.QueryTranslatorImpl.doCompile(QueryTranslatorImpl.java:206) 
    at org.hibernate.hql.ast.QueryTranslatorImpl.compile(QueryTranslatorImpl.java:136) 
    at org.hibernate.engine.query.HQLQueryPlan.<init>(HQLQueryPlan.java:101) 
    at org.hibernate.engine.query.HQLQueryPlan.<init>(HQLQueryPlan.java:80) 
    at org.hibernate.engine.query.QueryPlanCache.getHQLQueryPlan(QueryPlanCache.java:98) 
    at org.hibernate.impl.SessionFactoryImpl.checkNamedQueries(SessionFactoryImpl.java:557) 
    at org.hibernate.impl.SessionFactoryImpl.<init>(SessionFactoryImpl.java:422) 
    at org.hibernate.cfg.Configuration.buildSessionFactory(Configuration.java:1385) 
    at org.hibernate.cfg.AnnotationConfiguration.buildSessionFactory(AnnotationConfiguration.java:954) 
    at org.hibernate.ejb.Ejb3Configuration.buildEntityManagerFactory(Ejb3Configuration.java:883) 
    ... 55 more 

Trả lời

5

Câu trả lời là: không. Nó không thể xử lý nó. Đó là những gì nó nói.

Đối với các loại giá trị (thành phần hỗn hợp), nó thậm chí sẽ không hoạt động, bởi vì bạn không nhận được thông tin những gì thực sự thuộc về cùng một mục túi.

Thông thường nó thậm chí không có ý nghĩa. Nếu bạn truy vấn một bảng và nhận 10 bản ghi trong bảng bắt đầu, 10 trong túi đầu tiên và 10 bản ghi khác trong túi thứ hai, bạn sẽ lấy 1000 bản ghi chỉ để tạo 30 đối tượng này trong bộ nhớ. Hãy tưởng tượng số lượng hồ sơ khi có 100 bản ghi trong mỗi bảng (gợi ý: 1.000.000 thay vì 300) và khi bạn tìm nạp một túi khác (gợi ý: 100,000,000 thay vì 400) ...

Bằng cách này: nối tìm nạp có thể dẫn đến các hiệu ứng và vấn đề lạ và nên tránh, ngoại trừ bạn biết chính xác bạn đang làm gì.

+0

Cảm ơn! Đối với thời điểm này tôi thay thế nó bằng Set, nhưng tôi nghĩ rằng tôi sẽ cấu trúc lại giao diện vào ngày mai và hiển thị ít thông tin hơn. Cảm ơn vì bạn đã phản hồi! Làm thế nào bạn sẽ giải quyết nó khi bạn không có phạm vi kiên trì trong lối vào của bạn. Sử dụng các đối tượng truyền dữ liệu được xây dựng trong DAO thay vì các thực thể được tìm nạp? Tôi thừa kế dự án và tôi không được phép thực hiện những thay đổi lớn về thiết kế, cũng như tôi không được phép chuyển đổi nó sang j2ee. : -/ – mkuff

+0

Bạn có thể tắt tải chậm, điều này không tốt cho hiệu suất. Điều này lấy các túi ngay lập tức bằng các truy vấn riêng biệt. Bạn cũng có thể truy cập vào các túi (ví dụ như kích thước) để buộc tải. Các giải pháp hoàn hảo là tạo ra các phiên bên ngoài dao và giữ nó cho một giao dịch kinh doanh toàn bộ. (Tạo một phiên trong mỗi cuộc gọi đến dao được gọi là session-per-call và là một anti-pattern.) –

+0

Vì vậy, đây thực sự là một vấn đề bắt 22: nếu bạn không sử dụng tham gia tìm nạp, bạn nhận được vấn đề n + 1 hoặc ngoại lệ khởi tạo lười biếng. Phiên bên ngoài dao là một hack, trước hết bởi vì nó không nằm gần hợp đồng JPA và thứ hai vì nó không thể kiểm soát được, vì bạn không nên đưa ra bất kỳ giả định nào về tuổi thọ của thực thể tại thời điểm bạn tạo nó. Nó có thể trải qua một số yêu cầu, không nhất thiết phải http. – Deroude

1

Thay vì sử dụng Set, bạn có thể chia truy vấn và tải các thực thể trong các truy vấn khác nhau.
Ví dụ

From PointOfInterest p left join fetch p.labels WHERE p.figure = :figure 
    From PointOfInterest p left join fetch p.tags WHERE p.figure = :figure    

Vui lòng tham khảo the link

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