Đây thực sự là hành vi được mong đợi nếu tôi hiểu đúng cấu hình của bạn.
Hibernate không trả lại các kết quả khác biệt cho một truy vấn có bật tìm nạp kết hợp bên ngoài cho một tập hợp (ngay cả khi tôi sử dụng từ khóa riêng biệt)? Trước tiên, bạn cần hiểu SQL và cách OUTER JOIN hoạt động trong SQL. Nếu bạn không hiểu đầy đủ và hiểu các phép nối ngoài trong SQL, đừng tiếp tục đọc mục Câu hỏi thường gặp này mà hãy tham khảo sách hướng dẫn hoặc hướng dẫn SQL. Nếu không, bạn sẽ không hiểu lời giải thích sau đây và bạn sẽ phàn nàn về hành vi này trên diễn đàn Hibernate.
Các ví dụ điển hình có thể trả về các tham chiếu trùng lặp của cùng một đối tượng Order:
List result = session.createCriteria(Order.class)
.setFetchMode("lineItems", FetchMode.JOIN)
.list();
<class name="Order">
...
<set name="lineItems" fetch="join">
List result = session.createCriteria(Order.class)
.list();
List result = session.createQuery("select o from Order o left join fetch o.lineItems").list();
Tất cả các ví dụ này đều tạo ra cùng một câu lệnh SQL:
SELECT o.*, l.* from ORDER o LEFT OUTER JOIN LINE_ITEMS l ON o.ID = l.ORDER_ID
Bạn muốn biết tại sao có các bản sao ở đó? Nhìn vào tập kết quả SQL, Hibernate không ẩn các bản sao này ở bên trái của kết quả được nối bên ngoài nhưng trả về tất cả các bản sao của bảng lái xe. Nếu bạn có 5 đơn hàng trong cơ sở dữ liệu và mỗi đơn hàng có 3 mục hàng, tập hợp kết quả sẽ là 15 hàng. Danh sách kết quả Java của các truy vấn này sẽ có 15 phần tử, tất cả đều thuộc kiểu Order. Chỉ có 5 phiên bản Order sẽ được tạo bởi Hibernate, nhưng các bản sao của tập kết quả SQL được lưu giữ dưới dạng các tham chiếu trùng lặp đến 5 trường hợp này. Nếu bạn không hiểu câu cuối cùng này, bạn cần phải đọc trên Java và sự khác biệt giữa một cá thể trên Java heap và một tham chiếu đến một cá thể như vậy.
(Tại sao lại kết hợp ngoài cùng bên trái? Nếu bạn có một đơn đặt hàng bổ sung không có mục hàng, tập kết quả sẽ là 16 hàng với NULL lấp đầy phía bên phải, nơi dữ liệu mục hàng dành cho đơn đặt hàng khác. Bạn muốn đơn đặt hàng ngay cả khi họ không có mục hàng, phải không? Nếu không, hãy sử dụng tìm nạp kết hợp bên trong trong HQL của bạn).
Hibernate không lọc ra các tham chiếu trùng lặp này theo mặc định. Một số người (không phải bạn) thực sự muốn điều này. Làm thế nào bạn có thể lọc chúng ra?
Như thế này:
Collection result = new LinkedHashSet( session.create*(...).list() );