mundo - java and hibernate
Hibernate no puede obtener simultáneamente múltiples bolsas (11)
Alternativamente, agregue una anotación @Fetch específica de Hibernate a su código:
@OneToMany(mappedBy="parent", fetch=FetchType.EAGER)
@Fetch(value = FetchMode.SUBSELECT)
private List<Child> childs;
Esto debería solucionar el problema, relacionado con el error Hibernate HHH-1718
Hibernate lanza esta excepción durante la creación de SessionFactory:
org.hibernate.loader.MultipleBagFetchException: no se pueden recuperar varias bolsas simultáneamente
Este es mi caso de prueba:
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;
}
Niño.java
@Entity
public Child {
@Id
@GeneratedValue(strategy=GenerationType.IDENTITY)
private Long id;
@ManyToOne
private Parent parent;
}
¿Qué tal este problema? ¿Que puedo hacer?
EDITAR
OK, el problema que tengo es que otra entidad "padre" está dentro de mi padre, mi comportamiento real es este:
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;
}
A Hibernate no le gustan dos colecciones con FetchType.EAGER
, pero esto parece ser un error, no estoy haciendo cosas inusuales ...
Eliminar FetchType.EAGER
de Parent
u AnotherParent
resuelve el problema, pero lo necesito, por lo que la solución real es usar @LazyCollection(LazyCollectionOption.FALSE)
lugar de FetchType
(gracias a Bozho por la solución).
Creo que una versión más reciente de hibernate (compatible con JPA 2.0) debería manejar esto. Pero, de lo contrario, puede solucionarlo anotando los campos de la colección con:
@LazyCollection(LazyCollectionOption.FALSE)
Recuerde eliminar el atributo fetchType
de la anotación @*ToMany
.
Pero tenga en cuenta que en la mayoría de los casos un Set<Child>
es más apropiado que List<Child>
, así que a menos que realmente necesite un List
, vaya a Set
Cuando tiene objetos demasiado complejos con una colección de ahorro no puede ser una buena idea tenerlos todos con EAGER fetchType, use mejor LAZY y cuando realmente necesite cargar las colecciones use: Hibernate.initialize(parent.child)
para obtener los datos.
Después de probar con cada una de las opciones descritas en estas publicaciones y en otras, llegué a la conclusión de que la solución es la siguiente.
En cada lugar de XToMany @ XXXToMany(mappedBy="parent", fetch=FetchType.EAGER)
e XXXToMany(mappedBy="parent", fetch=FetchType.EAGER)
después
@Fetch(value = FetchMode.SUBSELECT)
Esto funciono para mi
Encontré una buena publicación del blog sobre el comportamiento de Hibernate en este tipo de asignaciones de objetos: http://blog.eyallupu.com/2010/06/hibernate-exception-simultaneously.html
La razón por la que obtienes esa excepción es que Hibernate terminaría haciendo un Producto Cartesiano que es malo para el rendimiento.
Ahora, aunque podría "arreglar" el problema utilizando Set
lugar de List
, no debería hacerlo porque el Producto Cartesiano todavía aparecerá en las declaraciones SQL subyacentes.
Es mejor que cambie de FetchType.EAGER
a Fetchype.LAZY
ya que la búsqueda ansiosa es una idea terrible que puede llevar a problemas críticos de rendimiento de la aplicación .
Si necesita buscar las entidades secundarias en una jerarquía multinivel, seleccione mejor desde el elemento más interno hasta los padres, como se explica en este artículo .
Para solucionarlo, simplemente tome Set
en lugar de List
para su objeto anidado.
@OneToMany
Set<Your_object> objectList;
y no olvides usar fetch=FetchType.EAGER
funcionará.
Hay un concepto más, CollectionId
en Hibernate, si desea quedarse solo con la lista.
Podrías usar una nueva anotación para resolver esto:
@XXXToXXX(targetEntity = XXXX.class, fetch = FetchType.LAZY)
De hecho, el valor predeterminado de fetch es FetchType.LAZY también.
Probamos Establecer en lugar de Lista y es una pesadilla: cuando agregas dos objetos nuevos, equals () y hashCode () fallan en distinguirlos. Porque no tienen ninguna identificación.
Las herramientas típicas como Eclipse generan ese tipo de código a partir de tablas de base de datos:
@Override
public int hashCode() {
final int prime = 31;
int result = 1;
result = prime * result + ((id == null) ? 0 : id.hashCode());
return result;
}
También puede leer este artículo que explica correctamente cómo JPA / Hibernate está desordenado. Después de leer esto, creo que esta es la última vez que uso un ORM en mi vida.
También me he topado con gente de Domain Driven Design que básicamente dice que ORM es una cosa terrible.
Simplemente cambie de tipo de List
tipo de Set
.
puede mantener las listas de EAGER en el stand en JPA y agregar al menos a una de ellas la anotación JPA @OrderColumn (con el nombre de un campo que debe solicitarse). No hay necesidad de anotaciones específicas de hibernación. Pero tenga en cuenta que podría crear elementos vacíos en la lista si el campo elegido no tiene valores a partir de 0
[...]
@OneToMany(mappedBy="parent", fetch=FetchType.EAGER)
@OrderColumn(name="orderIndex")
private List<Child> children;
[...]
en Niños entonces debes agregar el campo orderIndex