Jest to faktycznie oczekiwane zachowanie, jeśli poprawnie zrozumiałem twoją konfigurację.
Hibernate nie zwraca odrębnych wyników dla zapytania z włączonym pobieraniem sprzężenia zewnętrznego dla kolekcji (nawet jeśli używam odrębnego słowa kluczowego)? Po pierwsze, musisz zrozumieć SQL i jak działają OUTER JOIN w SQL. Jeśli nie rozumiesz w pełni i nie rozumiesz sprzężeń zewnętrznych w języku SQL, nie czytaj dalej tego artykułu FAQ, ale zapoznaj się z instrukcją lub samouczkiem SQL. W przeciwnym razie nie zrozumiesz następującego wyjaśnienia i będziesz narzekać na to zachowanie na forum Hibernate.
Typowe przykłady, które mogą zwrócić zduplikowane odwołania do tego samego obiektu 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();
Wszystkie te przykłady tworzą tę samą instrukcję SQL:
SELECT o.*, l.* from ORDER o LEFT OUTER JOIN LINE_ITEMS l ON o.ID = l.ORDER_ID
Chcesz wiedzieć, dlaczego istnieją duplikaty? Spójrz na zestaw wyników SQL. Hibernate nie ukrywa tych duplikatów po lewej stronie zewnętrznego połączonego wyniku, ale zwraca wszystkie duplikaty tabeli sterującej. Jeśli masz w bazie danych 5 zamówień, a każde zamówienie ma 3 pozycje, zestaw wyników będzie miał 15 wierszy. Lista wyników Java dla tych zapytań będzie zawierać 15 elementów, wszystkie typu Order. Tylko 5 instancji Order zostanie utworzonych przez Hibernate, ale duplikaty zestawu wyników SQL są zachowywane jako zduplikowane odwołania do tych 5 instancji. Jeśli nie rozumiesz tego ostatniego zdania, musisz poczytać o Javie i różnicy między instancją na stercie Java a odwołaniem do takiej instancji.
(Dlaczego lewe sprzężenie zewnętrzne? Jeśli miałbyś dodatkowe zamówienie bez elementów zamówienia, zestaw wyników składałby się z 16 wierszy z NULL wypełniającymi po prawej stronie, gdzie dane elementu zamówienia dotyczą innego zamówienia. Chcesz zamówień, nawet jeśli nie mają elementów zamówienia, prawda? Jeśli nie, użyj pobierania sprzężenia wewnętrznego w HQL).
Hibernate nie odfiltrowuje domyślnie tych zduplikowanych odniesień. Niektórzy ludzie (nie ty) naprawdę tego chcą. Jak możesz je odfiltrować?
Lubię to:
Collection result = new LinkedHashSet( session.create*(...).list() );