Будьте в спящем режиме Критерии возвращают детей многократно с FetchType. НЕТЕРПЕЛИВЫЙ

Я имею Order класс, который имеет список OrderTransactions и я отобразился, это с one-many В спящем режиме, отображаясь как так:

@OneToMany(targetEntity = OrderTransaction.class, cascade = CascadeType.ALL)
public List<OrderTransaction> getOrderTransactions() {
    return orderTransactions;
}

Они Orders также имеют поле orderStatus, который используется для фильтрации со следующими Критериями:

public List<Order> getOrderForProduct(OrderFilter orderFilter) {
    Criteria criteria = getHibernateSession()
            .createCriteria(Order.class)
            .add(Restrictions.in("orderStatus", orderFilter.getStatusesToShow()));
    return criteria.list();
}

Это работает, и результат как ожидалось.

Теперь вот мой вопрос: Да ведь когда я установил тип выборки явно на EAGER, сделайте Orders появляются многократно в получающемся списке?

@OneToMany(targetEntity = OrderTransaction.class, fetch = FetchType.EAGER, cascade = CascadeType.ALL)
public List<OrderTransaction> getOrderTransactions() {
    return orderTransactions;
}

Как я должен был бы изменить свой код Критериев для достижения того же результата с новой установкой?

113
задан Etienne Neveu 12 December 2016 в 09:13
поделиться

2 ответа

Если я правильно понял вашу конфигурацию, то это действительно ожидаемое поведение.

Вы получаете тот же самый экземпляр Order в любом из результатов, но так как сейчас вы делаете соединение с OrderTransaction, оно должно вернуть то же самое количество результатов, что и обычное соединение sql вернет

Так что на самом деле оно должно многократно повторяться. это очень хорошо объясняется самим автором (Гэвином Кингом) здесь: Это и объясняет, почему, и как еще можно получить четкие результаты


, также упомянутые в Hibernate FAQ :

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() );
113
ответ дан 24 November 2019 в 02:40
поделиться

Помимо того, что упомянул Eran, еще один способ получить желаемое поведение - установить трансформатор результата:

criteria.setResultTransformer(Criteria.DISTINCT_ROOT_ENTITY);
92
ответ дан 24 November 2019 в 02:40
поделиться
Другие вопросы по тегам:

Похожие вопросы: