Hibernate no puede alcanzar simultáneamente múltiples bolsas
-
30-09-2019 - |
Pregunta
Hibernate emite esta excepción durante la creación SessionFactory:
org.hibernate.loader.MultipleBagFetchException: No se pueden obtener simultáneamente múltiples bolsas
Esta 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;
}
Child.java
@Entity
public Child {
@Id
@GeneratedValue(strategy=GenerationType.IDENTITY)
private Long id;
@ManyToOne
private Parent parent;
}
¿Qué hay de este problema? ¿Qué puedo hacer?
Editar
correcto, el problema que tengo es que otra entidad "padre" está dentro de mis padres, mi comportamiento real es la siguiente:
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 no lo hace como dos colecciones con FetchType.EAGER
, pero esto parece ser un error, no estoy haciendo cosas inusuales ...
Extracción de FetchType.EAGER
Parent
o AnotherParent
resuelve el problema, pero lo necesito, por lo verdadera solución es utilizar @LazyCollection(LazyCollectionOption.FALSE)
en lugar de FetchType
(gracias a Bozho para la solución).
Solución
creo una versión más reciente de hibernación (con soporte para JPA 2.0) debe manejar esto. Pero por lo demás se puede trabajar en torno al anotar los campos de recolección con:
@LazyCollection(LazyCollectionOption.FALSE)
Recuerde que para quitar el atributo fetchType
partir 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 necesita un List
- go para Set
Otros consejos
Simplemente cambiar de un tipo a List
tipo Set
.
Añadir una anotación de Hibernate @Fetch-específica de 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 la hibernación fallo HHH-1718
Después de probar con cada opción única de describir en este postes y otros, llegó a la conclusión de que la solución del proceso es como sigue.
En cada lugar XToMany @XXXToMany(mappedBy="parent", fetch=FetchType.EAGER)
y de forma intermedia después de
@Fetch(value = FetchMode.SUBSELECT)
Esto funcionó para mí
Para solucionarlo simplemente tomar Set
en lugar de List
para su objeto anidado.
@OneToMany
Set<Your_object> objectList;
y no se olvide de usar fetch=FetchType.EAGER
va a trabajar.
Hay un concepto más CollectionId
en Hibernate si desea seguir con la lista única.
He encontrado un buen blog post sobre el comportamiento de Hibernate en este tipo de asignaciones de objetos: http : //blog.eyallupu.com/2010/06/hibernate-exception-simultaneously.html
puede mantener listas de cabina EAGER en APP y añadir a por lo menos uno de ellos la anotación JPA @OrderColumn (con, obviamente, el nombre de un campo a ser pedido). No hay necesidad de anotaciones de hibernación específicos. Pero hay que tener en cuenta que podría crear elementos vacíos en la lista si el campo elegido no tiene los valores a partir de 0
[...]
@OneToMany(mappedBy="parent", fetch=FetchType.EAGER)
@OrderColumn(name="orderIndex")
private List<Child> children;
[...]
en niños entonces usted debe agregar el campo orderIndex
La razón por la que recibe esa excepción es que Hibernate podría terminar haciendo un producto cartesiano que es malo para el rendimiento.
Ahora, si bien se puede "arreglar" el problema utilizando Set
en lugar de List
, no deberías hacer eso porque el producto cartesiano todavía será presentado en las sentencias SQL subyacentes.
Usted es mejor cambiar de FetchType.EAGER
a Fetchype.LAZY
puesto recuperación temprana es un idea terrible que puede conducir a problemas de rendimiento de aplicaciones críticas .
Si necesita buscar a los entidades secundarias a través de una jerarquía de niveles múltiples, mejor elegir la más interior niño hasta los padres, como se explica en este artículo .
Cuando tiene objetos muy complejos con la colección de saveral no podría ser buena idea tener todos ellos con fetchType Eager, un mejor uso perezoso y cuando realmente se necesita para cargar las colecciones utiliza:. Hibernate.initialize(parent.child)
para ir a buscar los datos
Tratamos Set en lugar de Lista ??strong> y es una pesadilla: cuando se agrega dos nuevos objetos, es igual a () y hashCode () no distinguen los dos! Debido a que no tiene ninguna ID.
herramientas típicas como Eclipse generar ese tipo de código de tablas de bases 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 adecuadamente la forma en mal estado JPA / Hibernate es. Después de leer esto, creo que esta es la última vez que utilizo cualquier ORM en mi vida.
He encontramos también con dominio Driven Design chicos que básicamente dicen ORM son una cosa terrible.
Para mí, el problema fue haber anidado EAGER recuperaciones.
Una solución es establecer los campos anidados a LAZY y utilizar Hibernate.initialize () para cargar el campo anidada (s):
x = session.get(ClassName.class, id);
Hibernate.initialize(x.getNestedField());
Se podría utilizar una nueva anotación para resolver esto:
@XXXToXXX(targetEntity = XXXX.class, fetch = FetchType.LAZY)
De hecho, se ha podido recuperar del valor por defecto es FetchType.LAZY también.