Спящий режим не может одновременно извлекать несколько пакетов
Hibernate выбрасывает это исключение во время создания SessionFactory:
org.hibernate.loader.MultipleBagFetchException: не может одновременно извлекать несколько пакетов
Это мой тестовый пример:
Parent.java
@Entity
public Parent {
@Id
@GeneratedValue(strategy=GenerationType.IDENTITY)
private Long id;
@OneToMany(mappedBy="parent", fetch=FetchType.EAGER)
// @IndexColumn(name="INDEX_COL") if I had this the problem solve but I retrieve more children than I have, one child is null.
private List<Child> children;
}
Child.java
@Entity
public Child {
@Id
@GeneratedValue(strategy=GenerationType.IDENTITY)
private Long id;
@ManyToOne
private Parent parent;
}
Как насчет этой проблемы? Что я могу сделать?
ИЗМЕНИТЬ
Хорошо, проблема заключается в том, что другой родительский объект внутри моего родителя, мое реальное поведение таково:
Parent.java
@Entity
public Parent {
@Id
@GeneratedValue(strategy=GenerationType.IDENTITY)
private Long id;
@ManyToOne
private AntoherParent anotherParent;
@OneToMany(mappedBy="parent", fetch=FetchType.EAGER)
private List<Child> children;
}
AnotherParent.java
@Entity
public AntoherParent {
@Id
@GeneratedValue(strategy=GenerationType.IDENTITY)
private Long id;
@OneToMany(mappedBy="parent", fetch=FetchType.EAGER)
private List<AnotherChild> anotherChildren;
}
Hibernate не любит две коллекции с FetchType.EAGER
, но это кажется ошибкой, я не делаю необычных вещей...
Удаление FetchType.EAGER
из Parent
или AnotherParent
решает проблему, но мне это нужно, поэтому реальное решение заключается в использовании @LazyCollection(LazyCollectionOption.FALSE)
вместо FetchType
(благодаря Bozho для решения).
Ответы
Ответ 1
Я думаю, что более новая версия hibernate (поддерживающая JPA 2.0) должна справиться с этим. Но в противном случае вы можете использовать его, аннотируя поля коллекции:
@LazyCollection(LazyCollectionOption.FALSE)
Не забудьте удалить атрибут fetchType
из аннотации @*ToMany
.
Но обратите внимание, что в большинстве случаев a Set<Child>
более подходит, чем List<Child>
, поэтому, если вам действительно не нужен List
- перейти для Set
Ответ 2
Просто измените тип List
на тип Set
.
Ответ 3
Добавьте специфичную для Hibernate аннотацию @Fetch в свой код:
@OneToMany(mappedBy="parent", fetch=FetchType.EAGER)
@Fetch(value = FetchMode.SUBSELECT)
private List<Child> childs;
Это должно исправить проблему, связанную с ошибкой Hibernate HHH-1718
Ответ 4
После того, как каждый отдельный параметр описал в этих сообщениях и других, я пришел к выводу, что исправление следующее.
В каждом месте XToMany @XXXToMany(mappedBy="parent", fetch=FetchType.EAGER)
и промежуточно после
@Fetch(value = FetchMode.SUBSELECT)
Это сработало для меня
Ответ 5
Чтобы исправить это, просто возьмите Set
вместо List
для вашего вложенного объекта.
@OneToMany
Set<Your_object> objectList;
и не забудьте использовать fetch=FetchType.EAGER
он будет работать.
В Hibernate есть еще одно понятие CollectionId
, если вы хотите придерживаться только списка.
Ответ 6
Я нашел хорошую запись в блоге о поведении Hibernate в таких отображениях объектов: http://blog.eyallupu.com/2010/06/hibernate-exception-simultaneously.html
Ответ 7
вы можете оставить списки EAGER в JPA и добавить хотя бы одну из них аннотацию JPA @OrderColumn (с явно именем поля, которое нужно заказать). Нет необходимости в конкретных аннотациях спящего режима.
Но имейте в виду, что он мог создавать пустые элементы в списке, если выбранное поле не имеет значений, начиная с 0
[...]
@OneToMany(mappedBy="parent", fetch=FetchType.EAGER)
@OrderColumn(name="orderIndex")
private List<Child> children;
[...]
в Children, тогда вы должны добавить поле orderIndex
Ответ 8
Причина, по которой вы получаете это исключение, заключается в том, что Hibernate в конечном итоге сделает декартово произведение, которое ухудшает производительность.
Теперь, хотя вы могли бы "исправить" проблему, используя Set
вместо List
, вы не должны этого делать, потому что декартово произведение все равно будет включено в базовые операторы SQL.
Вам лучше переключиться с FetchType.EAGER
на Fetchype.LAZY
так как Fetchype.LAZY
выборка - ужасная идея, которая может привести к критическим проблемам производительности приложений.
Если вам нужно выбрать дочерние объекты по многоуровневой иерархии, лучше выбрать от самого внутреннего потомка до родителей, как описано в этой статье.
Ответ 9
Если у вас слишком сложные объекты с саверной коллекцией, не может быть хорошей идеей иметь все из них с Eetcher fetchType, лучше использовать LAZY, и когда вам действительно нужно загружать коллекцию, используйте: Hibernate.initialize(parent.child)
для извлечения данных.
Ответ 10
Мы попробовали Set вместо List, и это кошмар: когда вы добавляете два новых объекта, equals() и hashCode() не могут различить их оба! Потому что у них нет идентификатора.
Типичные инструменты, такие как Eclipse, генерируют такой код из таблиц базы данных:
@Override
public int hashCode() {
final int prime = 31;
int result = 1;
result = prime * result + ((id == null) ? 0 : id.hashCode());
return result;
}
Вы также можете прочитать эту статью, которая правильно объясняет, как испортился JPA/Hibernate. Прочитав это, я думаю, что это последний раз, когда я использую ORM в своей жизни.
Я также встречал ребят из Domain Driven Design, которые в основном говорят, что ORM - ужасная вещь.
Ответ 11
Для меня проблема заключалась в том, чтобы иметь вложенные EAGER выборки.
Одно из решений - установить для вложенных полей значение LAZY и использовать Hibernate.initialize() для загрузки вложенных полей:
x = session.get(ClassName.class, id);
Hibernate.initialize(x.getNestedField());
Ответ 12
Вы можете использовать новую аннотацию, чтобы решить эту проблему:
@XXXToXXX(targetEntity = XXXX.class, fetch = FetchType.LAZY)
Фактически, для получения значения по умолчанию используется FetchType.LAZY.