Единственный способ действительно гарантировать - использовать Set
или SortedSet
в этих коллекциях вместо использования List
. Официально нет другого способа избежать этой проблемы с помощью Hibernate:
@OneToMany
private Set<AttributeY> attributeY;
Вы можете прочитать этот совет в старой документации Hibernate :
Запросы, использующие активное извлечение коллекций, обычно возвращают
дубликаты корневых объектов, но с их коллекциями
инициализируется. Вы можете отфильтровать эти дубликаты с помощью набора.
Или какая-то ссылка для той же проблемы на новее :
Единственное отличие состоит в том, что Set не допускает дублирование, но это
ограничение применяется контрактом объекта Java, а не
отображение базы данных.
Набор и заказ
Если вы хотите использовать Set
и контролировать порядок объектов, вы можете использовать SortedSet
и реализует Comparable
для дочерних объектов:
@OneToMany
@SortNatural
private SortedSet<AttributeY> attributeY = new TreeSet<>();
И
@Entity
public class AttributeY implements Comparable<AttributeY> {
@Override
public int compareTo(AttributeY o) {
return number.compareTo( o.getNumber() );
}
}
Для пользовательской логики сортировки вы можете использовать @SortComparator
.
Меры предосторожности
Без подробностей трудно сказать, почему это происходит в некоторых случаях с использованием List
, а в других - нет. Но вы можете попробовать реализовать методы equals
/ hashCode
, используя «бизнес-ключ» сущности:
При использовании наборов очень важно указывать правильные equals / hashCode
реализации для дочерних объектов. При отсутствии обычая
Логика реализации equals / hashCode, Hibernate будет использовать по умолчанию
Равенство объектов на основе ссылок Java, которое может сделать неожиданным
результаты при смешивании экземпляров отсоединенного и управляемого объекта.
Кроме того, вы применяете условие, используя FETCH
псевдоним pv
и anteil
. Не делай этого . И избавьтесь от «крушения поезда» на вашем JPQL (anteil.attributeD.attributeE.id
), потому что это может заставить Hibernate создавать странные SQL-запросы (например, делать одно и то же JOIN более одного раза или неверные SQL-запросы). Итак, сделайте JOIN-файлы явными и не используйте псевдоним FETCH
для WHERE
:
LEFT JOIN FETCH z.attributeX
LEFT JOIN FETCH pv.attributeY
LEFT JOIN FETCH z.attributeB kma
LEFT JOIN FETCH kma.attributeC
LEFT JOIN pv.attributeY anteil
LEFT JOIN anteil.attributeD attributeD
LEFT JOIN attributeD.attributeE attributeE
LEFT JOIN z.attributeX pv
LEFT JOIN pv.attributeG attributeG
WHERE attributeE.id = :eId
AND attributeG.id = :gId
Если дублирование было в корневой сущности TableA
, DISTINCT
поможет, но это не ваш случай.