2011-12-15 47 views
11

Tôi có nhiều thực thể được truy vấn thông qua Truy vấn Tiêu chí JPA2.Cách lấy tất cả dữ liệu trong một truy vấn

tôi có thể tham gia hai trong số các tổ chức và nhận được kết quả ngay lập tức:

CriteriaBuilder criteriaBuilder = em.getCriteriaBuilder(); 
CriteriaQuery<LadungRgvorschlag> criteriaQuery = criteriaBuilder.createQuery(LadungRgvorschlag.class); 
Root<LadungRgvorschlag> from = criteriaQuery.from(LadungRgvorschlag.class); 
Join<Object, Object> ladung = from.join("ladung"); 

from.fetch("ladung", JoinType.INNER); 

Sau đó, tôi cố gắng để tham gia vào một bảng bổ sung như thế:

ladung.join("ladBerechnet"); 
ladung.fetch("ladBerechnet", JoinType.LEFT); 

tôi nhận được lỗi sau :

org.hibernate.QueryException: query specified join fetching, but the owner of the fetched association was not present in the select list [FromElement{explicit,not a collection join,fetch join,fetch non-lazy properties,classAlias=generatedAlias3,role=null,tableName=ladberechnet,tableAlias=ladberechn3_,origin=ladungen ladung1_,columns={ladung1_.id ,className=de.schuechen.beans.tms.master.LadBerechnet}}] [select generatedAlias0 from de.schuechen.beans.tms.master.LadungRgvorschlag as generatedAlias0 inner join generatedAlias0.ladung as generatedAlias1 inner join generatedAlias1.ladBerechnet as generatedAlias2 left join fetch generatedAlias1.ladBerechnet as generatedAlias3 inner join fetch generatedAlias0.ladung as generatedAlias4 where (generatedAlias0.erledigt is null) and (generatedAlias0.belegart in (:param0, :param1)) and (generatedAlias1.fzadresse in (:param2, :param3)) and (generatedAlias1.zudatum<=:param4) and (1=1) order by generatedAlias0.belegart asc, generatedAlias1.fzadresse asc, generatedAlias1.zudatum asc, generatedAlias1.zulkw asc] 

Làm cách nào tôi có thể cho JPA/Hibernate biết rằng bạn nên chọn tất cả các thực thể cùng một lúc?

Trả lời

6

không gì nói đến JPA, bạn có thể chuỗi tham gia fetches trong các truy vấn Tiêu chuẩn API (trích dẫn từ đặc điểm kỹ thuật):

An association or attribute referenced by the fetch method must be referenced from an entity or embeddable that is returned as the result of the query. A fetch join has the same join semantics as the corresponding inner or outer join, except that the related objects are not top-level objects in the query result and cannot be referenced elsewhere by the query.

Và nó cũng không được hỗ trợ trong các truy vấn JPQL:

The association referenced by the right side of the FETCH JOIN clause must be an association or element collection that is referenced from an entity or embeddable that is returned as a result of the query.

It is not permitted to specify an identification variable for the objects referenced by the right side of the FETCH JOIN clause, and hence references to the implicitly fetched entities or elements cannot appear elsewhere in the query.

Với HQL có vẻ như có thể: Hibernate documentation EclipseLink không cung cấp phần mở rộng như vậy, do đó cú pháp của truy vấn sau được chấp nhận bởi Hibernate, nhưng không phải bởi EclipseLink:

SELECT a FROM A a LEFT JOIN FETCH a.bb b LEFT JOIN FETCH b.cc 

Trong EclipseLink cùng có thể được thực hiện qua query hints.

11

Với JPA 'một số phương ngữ của JPA' bạn có thể ghép nối các lần tìm nạp, nhưng tôi không nghĩ bạn có thể/nên thực hiện cả phép nối và tìm nạp tham gia.

Ví dụ, nếu chúng ta có một Program rằng có một-nhiều mối quan hệ với một Reward mà có một mối quan hệ với một Duration, các JPQL sau sẽ nhận được một trường hợp cụ thể với các phần thưởng và thời gian pre vời:

SELECT DISTINCT 
    program 
FROM 
    Program _program 
     LEFT JOIN FETCH 
    _program.rewards _reward 
     LEFT JOIN FETCH 
    _reward.duration _duration 
WHERE 
    _program.id = :programId 

} 

với mã tiêu chuẩn tương đương:

CriteriaBuilder criteriaBuilder = entityManager.getCriteriaBuilder(); 
CriteriaQuery<Program> criteriaQuery = criteriaBuilder.createQuery(Program.class); 
Root<Program> root = criteriaQuery.from(Program.class); 

Fetch<Program, Reward> reward = root.fetch("rewards", JoinType.LEFT); 
Fetch<Reward, Duration> duration = reward.fetch("duration", JoinType.LEFT); 

criteriaQuery.where(criteriaBuilder.equal(root.get("id"), programId)); 

TypedQuery<program> query = entityManager.createQuery(criteriaQuery); 

return query.getSingleResult(); 

Lưu ý rằng các biến thưởng và thời gian trung gian không cần thiết ở đây, nhưng chúng nhô cho mục đích thông tin. root.fetch("rewards", JoinType.LEFT).fetch("duration", JoinType.LEFT) sẽ có tác dụng tương tự.

+0

Nó hoạt động vì các tiện ích mở rộng của nhà cung cấp trong một số triển khai (ví dụ như Hibernate chẳng hạn). Trong JPA nói chung truy vấn JPQL này không hoạt động, bởi vì một chuỗi và bí danh như vậy trong trường hợp này không bắt buộc phải được hỗ trợ theo đặc tả. –

+1

Cảm ơn Mikko đã làm rõ. Đó là khá khó chịu mà phần mở rộng như vậy được kích hoạt âm thầm, vì vậy bạn sử dụng chúng mà không thực sự nhận ra nó. –

+0

Cảm ơn cho đến nay. Sử dụng tìm nạp mà không cần sử dụng phép nối trước khi giải quyết vấn đề. Tuy nhiên, tôi muốn đặt một vị từ trên bảng đã nối. làm thế nào tôi có thể làm điều đó? Trước khi tôi sử dụng cấu trúc sau: Tham gia ladung = from.join ("ladung"); ladung.get ("fzadresse"). (Adressen); – Stinnux

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