Я имею Order
класс, который имеет список OrderTransactions
и я отобразился, это с one-many В спящем режиме, отображаясь как так:
@OneToMany(targetEntity = OrderTransaction.class, cascade = CascadeType.ALL)
public List<OrderTransaction> getOrderTransactions() {
return orderTransactions;
}
Они Order
s также имеют поле orderStatus
, который используется для фильтрации со следующими Критериями:
public List<Order> getOrderForProduct(OrderFilter orderFilter) {
Criteria criteria = getHibernateSession()
.createCriteria(Order.class)
.add(Restrictions.in("orderStatus", orderFilter.getStatusesToShow()));
return criteria.list();
}
Это работает, и результат как ожидалось.
Теперь вот мой вопрос: Да ведь когда я установил тип выборки явно на EAGER
, сделайте Order
s появляются многократно в получающемся списке?
@OneToMany(targetEntity = OrderTransaction.class, fetch = FetchType.EAGER, cascade = CascadeType.ALL)
public List<OrderTransaction> getOrderTransactions() {
return orderTransactions;
}
Как я должен был бы изменить свой код Критериев для достижения того же результата с новой установкой?
Если я правильно понял вашу конфигурацию, то это действительно ожидаемое поведение.
Вы получаете тот же самый экземпляр Order
в любом из результатов, но так как сейчас вы делаете соединение с OrderTransaction
, оно должно вернуть то же самое количество результатов, что и обычное соединение sql вернет
Так что на самом деле оно должно многократно повторяться. это очень хорошо объясняется самим автором (Гэвином Кингом) здесь: Это и объясняет, почему, и как еще можно получить четкие результаты
Hibernate не возвращает отчетливых результатов для запроса с включенной функцией извлечения внешних соединений для коллекции (даже если я использую отчетливые результаты ключевое слово)? Во-первых, Вам необходимо понять SQL и как работают ВНЕШИЕ СОВЕТЫ. на SQL. Если вы не до конца понимаете и понимаете внешние соединения в SQL, не продолжайте читать этот пункт FAQ, но ознакомьтесь с руководством по SQL или учебное пособие. В противном случае вы не поймете следующее объяснение. и вы пожалуетесь на такое поведение на форуме Hibernate.
Типичные примеры, которые могут возвращать дубликаты одних и тех же ссылок. Объект ордера:
List result = session.createCriteria(Order.class) .setFetchMode("lineItems", FetchMode.JOIN) .list();
<наименование класса="Заказ"> ...
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.* из ORDER o LEFT OUTER JOIN LINE_ITEMS l ON o.ID = l.ORDER_ID
Хочешь знать, почему там дубликаты? Посмотрите на результаты SQL, Hibernate не скрывает эти дубликаты на левой стороне внешней. объединенный результат, но возвращает все дубликаты таблицы вождения. Если у вас есть 5 заказов в базе данных, и каждый заказ имеет 3 строки, результат будет 15 строк. Java-список результатов этих запросов будет иметь 15 элементов, все по типу "Порядок". Только 5 экземпляров заказа будут создаются Hibernate, но дубликаты SQL resultet являются сохранены как дубликаты ссылок на эти 5 экземпляров. Если вы этого не сделаете Поймите это последнее предложение, вам нужно прочитать на Java и на разница между экземпляром на Java куче и ссылкой на такой пример.
(Почему левое внешнее соединение? Если бы у вас был дополнительный заказ без строки... элементы, результирующий набор будет 16 строк с NULL заполнением справа. сторона, где данные по линейным позициям для другого порядка. Вам нужны заказы даже если у них нет строк, верно? Если нет, используйте внутреннее соединение fetch в HQL).
Hibernate не отфильтровывает эти дубликаты ссылок по умолчанию. Некоторые люди (не вы) действительно хотят этого. Как их отфильтровать?
Например:
Collection result = new LinkedHashSet( session.create*(...).list() );
Помимо того, что упомянул Eran, еще один способ получить желаемое поведение - установить трансформатор результата:
criteria.setResultTransformer(Criteria.DISTINCT_ROOT_ENTITY);