2013-05-21 35 views
7

Tôi không nghĩ rằng mình sẽ hiểu đầy đủ về các lần tìm nạp.Làm cách nào để thực hiện tìm nạp "sâu" trong JPQL?

Tôi có truy vấn nơi tôi đang cố gắng háo hức "thổi phồng" tham chiếu xuống hai cấp.

Đó là, tôi A có một tùy chọn Collection của B s, và mỗi B có 0 hoặc 1 C. Kích thước của bộ sưu tập B được biết là nhỏ (10-20 ngọn). Tôi muốn tìm nạp trước biểu đồ này.

A quan hệ B được đánh dấu là FetchType.LAZY và là tùy chọn. Mối quan hệ của B với C cũng là tùy chọn và FetchType.LAZY.

Tôi đã hy vọng tôi có thể làm:

SELECT a 
    FROM A a 
    LEFT JOIN FETCH a.bs // look, no alias; JPQL forbids it 
    LEFT JOIN a.bs b // "repeated" join necessary since you can't alias fetch joins 
    LEFT JOIN FETCH b.c // this doesn't seem to do anything 
WHERE a.id = :id 

Khi tôi chạy này, tôi thấy rằng A s B bộ sưu tập thực sự lấy (tôi nhìn thấy một LEFT JOIN trong SQL tham khảo bảng để mà B được ánh xạ) .

Tuy nhiên, tôi không thấy bằng chứng nào cho thấy bảng của C được tìm nạp.

Làm cách nào tôi có thể tìm nạp trước tất cả C s và tất cả B s và tất cả C s có thể truy cập được từ một số A nhất định? Tôi không thể nhìn thấy bất kỳ cách nào để làm điều này.

+1

JPA gì làm bạn sử dụng không? Có những gợi ý có sẵn trong EclipseLink chính xác cho loại chức năng này. Xem các gợi ý 'eclipselink.join-fetch' và' eclipselink.batch' ... – Cascader

+0

Cảm ơn bạn. Nếu tôi sử dụng 'eclipselink.join-fetch', có vẻ như tôi chỉ được phép đặt một thuộc tính. Đúng không? Ví dụ, nếu tôi thổi vốn 'join-fetch' của mình vào' a.bs.c', thì nếu tôi cũng muốn tham gia tìm nạp — hãy nói — 'a.bs.d' tôi sẽ không may mắn. Đúng? –

+0

Ồ, điều này thật thú vị. Tài liệu EclipseLink (http://wiki.eclipse.org/EclipseLink/UserGuide/JPA/Basic_JPA_Development/Query_Hints#Join_Fetch) không nói rằng các phím gợi ý truy vấn trùng lặp là có thể nhưng có lẽ chúng là? Xem liên kết thú vị này: https://github.com/mysema/querydsl/issues/348 –

Trả lời

5

Các JPA spec không cho phép aliasing một lấy tham gia, nhưng một số nhà cung cấp JPA làm.

EclipseLink thực hiện như 2.4. EclipseLink cũng cho phép tìm nạp nối lồng nhau bằng cách sử dụng ký hiệu chấm (tức là "JOIN FETCH a.bs.c") và hỗ trợ gợi ý truy vấn "eclipselink.join-fetch" cho phép kết nối lồng nhau (bạn có thể chỉ định nhiều gợi ý cùng tên gợi ý)).

Nói chung, bạn cần phải cẩn thận khi sử dụng bí danh trên lần tìm nạp, vì bạn có thể ảnh hưởng đến dữ liệu được trả về.

Xem, http://java-persistence-performance.blogspot.com/2012/04/objects-vs-data-and-filtering-join.html

+0

Cảm ơn, @James; vì nhiều lý do khác nhau, chúng tôi cần giữ tiêu chuẩn JPQL của mình, vì vậy có vẻ như gợi ý truy vấn (chuỗi định dạng) cho tôi. Đáng chú ý là việc sử dụng một vài trong số các kết quả này trong một lỗi: https://bugs.eclipse.org/bugs/show_bug.cgi?id=408719 (cũng được báo cáo bởi người khác trong năm 2010 tại đây: https://forums.oracle. com/forums/thread.jspa? threadID = 847970.Tôi đang rất lo lắng về việc tìm nạp trước quá sâu, vì vậy có lẽ điều này là kỳ quặc cho điều tốt nhất. :-) –

+0

eclipselink.join-fetch cũng đang hoạt động trong eclipseLink 2.3: .setHint ("eclipselink.join-fetch", "a.bs.c") – tak3shi

4

JPA không cho phép nhập tham gia lồng nhau, cũng như không cho phép bí danh tham gia tìm nạp, vì vậy đây có thể là nhà cung cấp JPA cụ thể.

Trong EclipseLink, bạn có thể chỉ định gợi ý truy vấn để thực hiện tham gia lồng nhau tìm nạp.

Bạn không thể làm cho nó đệ quy trong JPQL mặc dù, bạn chỉ có thể đi ở mức tốt nhất n. Trong EclipseLink bạn có thể sử dụng @JoinFetch hoặc @BatchFetch trên ánh xạ để thực hiện truy vấn đệ quy.

Xem, http://java-persistence-performance.blogspot.com/2010/08/batch-fetching-optimizing-object-graph.html

Nguồn: http://www.coderanch.com/t/570828/ORM/databases/Recursive-fetch-join-recursively-fetching

3

Tôi đang sử dụng Hibernate (và điều này có thể được cụ thể cho nó) và tôi đã thành công với điều này:

SELECT DISTINCT a, b 
FROM A a 
LEFT JOIN a.bs b 
LEFT JOIN FETCH a.bs 
LEFT JOIN FETCH b.c 
WHERE a.id = :id 

(Lưu ý b trong danh sách lựa chọn).

Đây là cách duy nhất tôi thấy điều này sẽ làm việc cho tôi, lưu ý rằng đây trả Object[] cho tôi và sau đó tôi lọc nó trong mã như vậy:

cung cấp
(List<A>) q.getResultList().stream().map(pair -> (A) (((Object[])pair)[0])).distinct().collect(Collectors.toList());