Спящий режим не может одновременно извлекать несколько пакетов

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, если вы хотите придерживаться только списка.

Ответ 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.