На самом деле это ожидаемое поведение, если я правильно понял вашу конфигурацию.
Hibernate не возвращает отчетливых результатов для запроса с включенной выборкой внешнего соединения для коллекции (даже если я использую особое ключевое слово)? Во-первых, вам нужно понять SQL и то, как ВНЕШНИЕ СОЕДИНЕНИЯ работают в SQL. Если вы не полностью понимаете и не понимаете внешние соединения в SQL, не продолжайте читать этот элемент часто задаваемых вопросов, а обратитесь к руководству или учебному пособию по SQL. В противном случае вы не поймете следующее объяснение и пожалуетесь на такое поведение на форуме Hibernate.
Типичные примеры, которые могут возвращать повторяющиеся ссылки на один и тот же объект 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();
Все эти примеры создают один и тот же оператор SQL:
SELECT o.*, l.* from ORDER o LEFT OUTER JOIN LINE_ITEMS l ON o.ID = l.ORDER_ID
Хотите знать, почему там дубликаты? Посмотрите на набор результатов SQL, Hibernate не скрывает эти дубликаты в левой части внешнего объединенного результата, а возвращает все дубликаты управляющей таблицы. Если у вас есть 5 заказов в базе данных, и каждый заказ имеет 3 позиции, набор результатов будет 15 строк. Список результатов Java этих запросов будет содержать 15 элементов, все типа Order. Hibernate создает только 5 экземпляров Order, но дубликаты набора результатов SQL сохраняются как повторяющиеся ссылки на эти 5 экземпляров. Если вы не понимаете это последнее предложение, вам необходимо прочитать о Java и о различиях между экземпляром в куче Java и ссылкой на такой экземпляр.
(Почему левое внешнее соединение? Если бы у вас был дополнительный заказ без позиций, набор результатов был бы 16 строк с NULL, заполняющим правую часть, где данные позиции относятся к другому заказу. Вам нужны заказы, даже если у них нет позиций, не так ли? Если нет, используйте извлечение внутреннего соединения в вашем HQL).
По умолчанию Hibernate не отфильтровывает эти повторяющиеся ссылки. Некоторые люди (не вы) действительно этого хотят. Как их отфильтровать?
Как это:
Collection result = new LinkedHashSet( session.create*(...).list() );