2012-06-22 5 views
5

Một đồng nghiệp của tôi đã như sau (hình như không hợp lệ) truy vấn JPQL:Trong JPA 2.0 JPQL, khi một trả về một đối tượng MỚI, làm thế nào người ta có thể sử dụng FETCH JOIN?

SELECT NEW com.foobar.jpa.DonationAllocationDTOEntity(a.id, a.campaign, a.campAppeal, a.campDivision, a.divisionFund) 
FROM DonationAllocation a JOIN a.donation d JOIN a.allocationType t 
JOIN FETCH a.campaign 
WHERE d.id = :donationId 
AND (t.code = 'Pledge' OR t.code = 'MatchingPledge') 

Nó là đáng chú ý (cho sau này trong bài viết này) rằng mối quan hệ DonationAllocation 's với một thực thể Campaign là nhiều-to-one, và được đánh dấu là FetchType.LAZY. Mục đích của đồng nghiệp của tôi với truy vấn này là để (trong số những thứ khác) đảm bảo rằng a.campaign là "thổi phồng" (háo hức tìm nạp).

Hibernate (rõ ràng chỉ là một JPA thi hành một số), khi đối mặt với truy vấn này, nói:

query specified join fetching, but the owner of the fetched association was not present in the select list

này có ý nghĩa, như danh sách lựa chọn chỉ chứa NEW DonationAllocationDTOEntity(), và phần 4.4.5.3 đặc điểm kỹ thuật JPA 2.0 cho biết:

Kết hợp được tham chiếu bởi bên phải của mệnh đề FETCH JOIN phải là một bộ sưu tập liên kết hoặc phần tử được tham chiếu từ một thực thể hoặc một tệp có thể nhúng được trả lại do truy vấn.

Vì vậy, vì không có "thực thể hoặc nhúng được trả về như là kết quả của truy vấn" (đó là một DTO xây dựng sử dụng toán tử NEW), nó sau đó không có hiệp hội có thể cho một Fetch THAM GIA để tham khảo và do đó truy vấn này không hợp lệ.

Làm thế nào, với giới hạn này, nên xây dựng truy vấn JPQL trong trường hợp này sao cho a.campaign - được chuyển thành biểu thức hàm tạo - được tìm nạp háo hức?

Trả lời

2

Tôi chỉ đơn giản là chọn thực thể và liên kết của nó, và llopover kết quả để gọi constructor DTO một cách rõ ràng. Bạn sẽ có lợi thế bổ sung kiểm tra thời gian biên dịch và mã refactorable:

select a from DonationAllocation a 
JOIN a.donation d 
JOIN a.allocationType t 
JOIN FETCH a.campaign 
WHERE d.id = :donationId 
AND (t.code = 'Pledge' OR t.code = 'MatchingPledge') 

... 

for (DonationAllocation a : list) { 
    result.add(new DonationAllocationDTOEntity(a.id, 
               a.campaign, 
               a.campAppeal, 
               a.campDivision, 
               a.divisionFund)); 
} 

EDIT:

Truy vấn này cũng nên chọn những gì cần thiết, và tránh chọn các thực thể DonationAllocation toàn:

select a.id, a.campaign, a.campAppeal, a.campDivision, a.divisionFund 
from DonationAllocation a 
JOIN a.donation d 
JOIN a.allocationType t 
WHERE d.id = :donationId 
AND (t.code = 'Pledge' OR t.code = 'MatchingPledge') 

và bạn có thể chỉ cần thêm hàm tạo DTO vào truy vấn nếu bạn muốn:

select new com.foobar.jpa.DonationAllocationDTOEntity(a.id, a.campaign, a.campAppeal, a.campDivision, a.divisionFund) 
from DonationAllocation a 
JOIN a.donation d 
JOIN a.allocationType t 
WHERE d.id = :donationId 
AND (t.code = 'Pledge' OR t.code = 'MatchingPledge') 

Thực tế, chiến dịch a.campaign trong mệnh đề chọn phải đủ để cho Hibernate tải thực thể. Ít nhất đó là cách nó hoạt động trong các thử nghiệm của tôi.

+0

Cảm ơn bạn. 'DonationAllocation' hiện là một đối tượng * khổng lồ *, với quá nhiều mối quan hệ' EAGER'. Tôi tin rằng đồng nghiệp của tôi đang cố gắng lấy lại một số phần nhất định của nó. Nó chỉ như vậy sẽ xảy ra rằng một trong những mối quan hệ anh * không * trên thực tế muốn háo hức nạp trong truy vấn này. Với kiến ​​thức mới này, điều đó có thay đổi câu trả lời của bạn không? –

+0

Có, hãy xem câu trả lời của tôi. Nhưng nếu tải thực thể là một vấn đề như vậy, nó chỉ có nghĩa là các hiệp hội háo hức của nó nên được thực hiện lười biếng. Tôi thích làm mọi thứ lười biếng. –