Подтвердить что ты не робот

Множественные выборки с типом EAGER в Hibernate с JPA

У меня есть сущность, которая содержит:

@OneToMany(fetch = FetchType.EAGER, cascade = CascadeType.ALL, mappedBy = "assessment")
@OrderBy(value = "order ASC")
private List<AssessmentPart> assessmentParts = new LinkedList<>();

@OneToMany(fetch = FetchType.EAGER, cascade = CascadeType.ALL, mappedBy = "assessment")
private List<AssessmentText> texts = new LinkedList<>();

как вы видите, есть две коллекции, которые нужно загружать с нетерпением. Это не работает, а спящий режим выдает исключение:

Caused by: org.hibernate.loader.MultipleBagFetchException: cannot simultaneously fetch multiple bags

Это потому, что Hibernate не может получить несколько коллекций за один раз. Но если я изменяю List на Set и LinkedList на HashSet, эта часть работает нормально, а другая - более неприятная проблема.

Когда я пытаюсь получить сущность из базы данных, используя:

entityManager.find(entityClass, primaryKey);

Сбой:

org.hibernate.AssertionFailure: null identifier

Я уверен, что идентификатор, передаваемый методу find, не является нулевым, я отлаживался, и я уверен в этом. Это как-то исчезает внутри спящего режима.

Если я изменяю типы коллекций на LAZY, все работает без ошибок, но есть некоторые обстоятельства, когда мне нужно использовать EAGER.

Есть ли у кого-нибудь решение, как его исправить? Либо я мог бы иметь набор, но предотвращать ошибку утверждения, или я мог бы иметь список, но как-то избегать ошибок нескольких пакетов.

Я использую:

Hibernate 4.2.2.Final
Tomcat 7
JPA 2.0
JDK 1.7

ИЗМЕНИТЬ

Я только что обнаружил, что добавление @Fetch(FetchMode.SELECT) устраняет проблему, и я могу использовать несколько списков с типом EAGER, но все равно решить эту проблему, не используя специальные аннотации Hibernate? И почему это исправило проблему в первую очередь?

4b9b3361

Ответ 1

Основная причина проблемы заключается в том, что когда Hibernate извлекает результаты SQL-запроса, нет простого способа определить, какой дочерний элемент принадлежит к какой коллекции. См. эту запись в блоге для более подробного объяснения с примером. Подводя итог, вы имеете следующие обходные пути:

  • Загрузите каждую коллекцию отдельно с помощью подзапроса @Fetch(FetchMode.SELECT)
  • Принудительное использование списка вместо мешка путем добавления столбца индекса @IndexColumn(name="LIST_INDEX")
  • Используйте неупорядоченный сбор, например Set.

Ответ 2

Если вы используете Hibernate, и вам не нужны аннотации Hibernate:

Аннотировать поля вашей коллекции:

@LazyCollection(LazyCollectionOption.FALSE)

Не забудьте удалить атрибут fetchType из аннотации @OneToMany.