2011-08-24 11 views
5

Problema es que tengo dos bolsas en mi entidad que me gustaría mostrar en mi interfaz jsf (Spring en la parte posterior, por lo que no hay carga diferida). Así que tengo a buscar ansiosamente a mostrar la información en una lista como esta:Hibernate fetch join -> no se puede obtener varias bolsas

  • Punto 1 (etiqueta 1, etiqueta 2) (Tag1 ... Tag n)
  • Punto 2 (Label 3, Etiqueta 4) (Tag1 ... Tag n)

Poner ambas listas en entredicho no funcionó. Así que probé suerte con una unión fetch. Me permitió buscar una lista, pero cuando agregué la segunda lista, recibí el error conocido de "no puedo buscar varias bolsas".

¿Puede Hibernate manejar dos fetch joins en una consulta?

public class PointOfInterest 
@OneToMany(mappedBy="poi") 
private List<PointOfInterestLabel> labels = new ArrayList<PointOfInterestLabel>(); 

@ManyToMany 
private List<Tag> tags = new ArrayList<Tag>(); 

Mi fetch unirse:

SELECT DISTINCT p from PointOfInterest p 
     left join fetch p.labels 
     left join fetch p.tags WHERE p.figure = :figure 

En el inicio de la creación de mi fábrica de hibernación falla con:

Caused by: org.hibernate.loader.MultipleBagFetchException: cannot simultaneously fetch multiple bags 
    at org.hibernate.loader.BasicLoader.postInstantiate(BasicLoader.java:94) 
    at org.hibernate.loader.hql.QueryLoader.<init>(QueryLoader.java:123) 
    at org.hibernate.hql.ast.QueryTranslatorImpl.doCompile(QueryTranslatorImpl.java:206) 
    at org.hibernate.hql.ast.QueryTranslatorImpl.compile(QueryTranslatorImpl.java:136) 
    at org.hibernate.engine.query.HQLQueryPlan.<init>(HQLQueryPlan.java:101) 
    at org.hibernate.engine.query.HQLQueryPlan.<init>(HQLQueryPlan.java:80) 
    at org.hibernate.engine.query.QueryPlanCache.getHQLQueryPlan(QueryPlanCache.java:98) 
    at org.hibernate.impl.SessionFactoryImpl.checkNamedQueries(SessionFactoryImpl.java:557) 
    at org.hibernate.impl.SessionFactoryImpl.<init>(SessionFactoryImpl.java:422) 
    at org.hibernate.cfg.Configuration.buildSessionFactory(Configuration.java:1385) 
    at org.hibernate.cfg.AnnotationConfiguration.buildSessionFactory(AnnotationConfiguration.java:954) 
    at org.hibernate.ejb.Ejb3Configuration.buildEntityManagerFactory(Ejb3Configuration.java:883) 
    ... 55 more 

Respuesta

5

La respuesta es: no. No puede manejarlo. Eso es lo que dice.

Para los tipos de valor (elemento compuesto) ni siquiera funcionaría, porque no se obtiene la información de lo que realmente pertenece al mismo artículo de la bolsa.

Por lo general, ni siquiera tiene sentido. Si consulta una tabla y obtiene 10 registros en la tabla de inicio, 10 en la primera bolsa y otros 10 en la segunda bolsa, obtendrá 1000 registros solo para crear estos 30 objetos en la memoria. Imagine el número de registros cuando habría 100 registros en cada tabla (sugerencia: 1,000,000 en lugar de 300) y cuando busque junte otra bolsa (sugerencia: 100,000,000 en lugar de 400) ...

Por cierto: únete a buscar puede provocar efectos y problemas extraños y debe evitarse, excepto que usted sepa exactamente lo que está haciendo.

+0

Gracias! Por el momento lo reemplacé con Set, pero creo que voy a refactorizar la interfaz mañana y mostrar menos información. ¡Gracias por la respuesta! ¿Cómo lo resolverías cuando no tienes alcance de persistencia en tu interfaz? ¿Utiliza objetos de transferencia de datos integrados en el DAO en lugar de entidades extraídas? Heredé el proyecto y no tengo permitido hacer grandes cambios de diseño, ni puedo cambiarlo a j2ee. : -/ – mkuff

+0

Puede desactivar la carga diferida, lo cual es malo para el rendimiento. Esto recoge las bolsas de inmediato por consultas separadas. También puede acceder a las bolsas (por ejemplo, tamaño) para forzar la carga. La solución perfecta es crear la sesión fuera del dao y guardarla para una transacción comercial completa. (Crear una sesión en cada llamada al dao se llama sesión-por-llamada y es un antipatrón). –

+0

Así que realmente este es un problema de captura 22: si no usas búsqueda de unión, obtienes n + 1 problema o excepción de inicialización perezosa. La sesión fuera de dao es un truco, en primer lugar porque no está cerca del contrato de JPA y, en segundo lugar, porque es difícilmente controlable, ya que no debe hacer suposiciones sobre la vida de una entidad en el momento en que la crea. Puede abarcar varias solicitudes, no necesariamente http. – Deroude

1

En lugar de utilizar Set, puede dividir la consulta y cargar las entidades en diferentes consultas.
Ej

From PointOfInterest p left join fetch p.labels WHERE p.figure = :figure 
    From PointOfInterest p left join fetch p.tags WHERE p.figure = :figure    

Consulte the link

Cuestiones relacionadas