2010-06-29 29 views
5

Actualmente estoy moviendo una aplicación (de trabajo) de usar EclipseLink a Hibernate JPA, en su mayoría ha ido bastante bien, pero estoy encontrando una cosa que no puedo explicar, y también puedo ¡No pienses en ningún buen término de búsqueda!Hibernate JPA - Relación ManyToOne no poblada

Básicamente, tengo cuatro entidades, con relaciones de uno-a-muchos formando una cadena:

EntityA tiene una lista de EntityB de, cada uno de los cuales tiene una lista de EntityC de, cada uno de los cuales tiene una lista de EntityD de

cada uno de los que entonces tiene una relación muchos-a-uno en la otra dirección, por lo que:

EntityD tiene una EntityC, que tiene una EntityB, que tiene una EntityA.

que está (muy reducido para mayor claridad):

@Entity 
public class EntityA { 
    @OneToMany (cascade = CascadeType.All, mappedBy = "entityA") 
    private List<EntityB> entityBList; 
    ... 
} 

@Entity 
public class EntityB { 
    @OneToMany (cascade = CascadeType.All, mappedBy = "entityB") 
    private List<EntityC> entityCList; 

    @JoinColumn (name = "ENTITY_A", referencedColumnName = "ENTITY_A_ID") 
    @ManyToOne (cascade = CascadeType.PERSIST, optional = false) 
    private EntityA entityA; 
} 

@Entity 
public class EntityC { 
    @OneToMany (cascade = CascadeType.ALL, mappedBy = "entityC") 
    private List<EntityD> entityDList; 

    @JoinColumn (name = "ENTITY_B", referencedColumnName = "ENTITY_B_ID") 
    @ManyToOne (cascade = CascadeType.PERSIST, optional = false) 
    private EntityB entityB; 
} 

@Entity 
public class EntityD { 
    @JoinColumn (name = "ENTITY_C", referencedColumnName = "ENTITY_C_ID") 
    @ManyToOne (cascade = CascadeType.PERSIST, optional = false) 
    private EntityC entityC; 
} 

Obtengo un EntityA de la base de datos (mirando hacia arriba por su clave primaria), y por lo tanto obtener una instancia EntityA muy bien poblada, con una PersistentBag de mi List<EntityB>. Veo una carga lenta sucediendo cuando desreferenciamos ese List<EntityB>, y lo mismo se repite para obtener EntityCs de EntityB.

En este momento, todo es como esperaba, tengo una EntityA, B y C completamente llena con los valores de la base de datos, pero luego trato de obtener mi EntityD, desde EntityC, y encuentro que es nulo.

Mi administrador de entidades todavía está abierto y activo en este punto, e incluso si lo miro en el depurador inmediatamente después de obtener EntityA, puedo recorrer las relaciones, en cuanto a EntityC, y volver a ver el 'entityDList 'como nulo.

La única solución que he encontrado hasta ahora es utilizar:

EntityManager.refresh(entityC); 

que puebla todos sus elementos, incluyendo un PersistentBag cargado con pereza-para la entityDList.

Entonces, supongo que Hibernate solo está llenando las referencias 2 niveles de profundidad (o 3, dependiendo de cómo cuentes), y renunciar después de eso, aunque realmente no entiendo por qué sería eso. ¿Eso tiene sentido para alguien?

¿Hay alguna otra solución que la .refresh? ¿Algún tipo de valor de configuración o anotación que hará que Hibernate llene las referencias hasta el final?

+0

¿Cuál es el valor establecido para el parámetro de configuración de hibernación "max_fetch_depth"? –

Respuesta

2

Gracias a las sugerencias de la gente de aquí, que probablemente sean relevantes, pero no ayudaron en mi caso específico.

Si está leyendo esto experimentando el mismo problema, es probable que valga la pena intentar la sugerencia max_fetch_depth, pero por alguna razón no funcionó para mí (¿me gustaría sugerencias sobre por qué?).

Igualmente, si sus @ OneToMany's son Conjuntos, en lugar de Listas, hacer una búsqueda ansiosa o una combinación izquierda, como sugiere Albert podría funcionar, pero aparentemente Hibernate solo le permite tener un máximo de 1 Lista que se busca con impaciencia. si necesita más que eso, sus colecciones deben ser Conjuntos. No lo intenté, pero sospecho que podría haber resuelto el problema.

A menos que alguien tenga una mejor sugerencia, me quedaré con la actualización de llamadas, que en realidad probablemente tenga más sentido para mi aplicación de todos modos.

1

Esto es gracioso. Una forma de evitarlo sería consultar el objeto A left-join-fetching a -> B-> C-> D, que también es más rápido si vas a pasar al objeto D de todos modos. Sería algo como esto.

"from A left join fetch B left join fetch C left join fetch D" 

¿Has probado la relación entre C-> D eager? Curioso lo que sucederá entonces ...

+0

Gracias Albert, intenté ambas sugerencias, en vano :(Hacer la relación ansiosa no tuvo ningún efecto, así que traté de hacer las 3 relaciones (A-> B-> C-> D) ansiosas, pero Hibernate se quejó con "no se puede simultáneamente buscar varias bolsas ". La adición de uniones a la izquierda en JPQL tuvo el mismo resultado. He encontrado algo en otro lugar que sugiere que eso se debe a que las colecciones que estoy buscando son Listas, y que funcionaría si las hiciera Conjuntos, pero Soy demasiado flojo para hacer eso ahora, así que creo que voy a aguantar con una llamada de actualización! – DaveyDaveDave

1

Los documentos de hibernación dicen que puede establecerlo con la propiedad hibernate.max_fetch_depth. El valor predeterminado es 3. Puede encontrarlo en el "Hibernate Reference Documentation" en la página 47.

+0

Gracias por esto, ¿sabes si el archivo hibernate.properties también lo usa Hibernate JPA, no puedo encontrarlo? una respuesta en cualquier parte de los documentos de Hibernate. He intentado cambiarlo a 4 y también a 0, y parece no tener ningún efecto ... – DaveyDaveDave

+0

Bien, ignore lo anterior, parece que se está utilizando, porque al configurar max_fetch_depth para 0 se ha roto otras partes de mi aplicación :) Sin embargo, establecerlo en un número alto (lo he intentado con 4 y 10), no parece tener ningún efecto; Supongo que porque es solo un máximo, ¿y algo más está persuadiendo a Hibernate a detenerse en 3 niveles ...? – DaveyDaveDave

Cuestiones relacionadas