Hibernate (JPA) cómo hacer una consulta ansiosa, cargando todos los objetos secundarios

StackOverflow https://stackoverflow.com/questions/70992

  •  09-06-2019
  •  | 
  •  

Pregunta

Relativo a mi pregunta anterior, Quiero asegurarme de que todos los objetos secundarios estén cargados, ya que tengo varios subprocesos que pueden necesitar acceder a los datos (y así evitar excepciones de carga diferida).Entiendo que la forma de hacerlo es utilizar la palabra clave "buscar" en la consulta (EJB QL).Como esto:

select distinct o from Order o left join fetch o.orderLines

Suponiendo un modelo con Order clase que tiene un conjunto de OrderLines en eso.

Mi pregunta es que la palabra clave "distinta" parece ser necesaria ya que de lo contrario parece que obtengo un mensaje Order para cada OrderLine.¿Estoy haciendo lo correcto?

Quizás lo más importante sea: ¿hay alguna manera de atraer todos los objetos infantiles, sin importar cuán profundos sean?Tenemos alrededor de 10 a 15 clases y para el servidor necesitaremos todo cargado...Estaba evitando usar FetchType.EAGER ya que eso significa que siempre está ansioso y, en particular, la interfaz web carga todo, pero tal vez ese sea el camino a seguir, ¿es eso lo que haces?Creo recordar que intentamos esto antes y luego obtuvimos páginas web muy lentas, pero ¿quizás eso signifique que deberíamos usar un caché de segundo nivel?

¿Fue útil?

Solución

Cambiar la anotación es una mala idea en mi opinión.Como no se puede cambiar a diferido en tiempo de ejecución.Es mejor hacer que todo sea perezoso y buscarlo según sea necesario.

No estoy seguro de entender su problema sin asignaciones.La recuperación de unión izquierda debería ser todo lo que necesita para el caso de uso que describe.Por supuesto, obtendrá un pedido por cada línea de pedido si la línea de pedido tiene un pedido como padre.

Otros consejos

No estoy seguro de usar la palabra clave fetch en su EJBQL, es posible que la confunda con la anotación...

¿Has intentado agregar la propiedad FetchType a tu atributo de relación?

@OneToMany(fetch=FetchType.EAGER)?

Ver:

http://java.sun.com/javaee/5/docs/api/javax/persistence/FetchType.html http://www.jroller.com/eyallupu/entry/hibernate_exception_simultanefully_fetch_multiple

¿Has intentado usar un transformador de resultados?Si utiliza consultas de Criterios, puede aplicar un transformador de resultados (aunque hay algunos problemas con la paginación y el transformador de resultados.):

Criteria c = ((Session)em.getDelegate()).createCriteria(Order.class);
c.setResultTransformer(Criteria.DISTINCT_ROOT_ENTITY);
c.list();

el em.getDelegate() es un truco que sólo funciona si estás usando hibernación.

Quizás lo más importante, ¿hay alguna manera de atraer a todos los objetos infantiles, sin importar cuán profundo?Tenemos alrededor de 10-15 clases y para el servidor necesitaremos todo cargado ...Estaba evitando usar fetchtype.age, ya que eso significaba que siempre estaba ansioso y, en particular, el front -end de la web lo carga todo, pero tal vez ese es el camino a seguir, ¿es eso lo que haces?Parece que recordamos que intentamos esto antes y luego obteniendo páginas web realmente lentas, pero ¿tal vez eso significa que deberíamos usar un caché de segundo nivel?

Si todavía estás interesado, respondí una pregunta similar en este hilo. cómo serializar colecciones de hibernación.

Básicamente utilizas una utilidad llamada topadora que asigna beans a otros beans y, al hacerlo, activa todas sus cargas diferidas.Como puedes imaginar, esto funciona mejor si todas las colecciones se recuperan con entusiasmo.

Es posible que pueda hacer algo así utilizando una consulta de criterios (separada) y configurando el modo de recuperación.P.ej.,

Session s = ((HibernateEntityManager) em).getSession().getSessionFactory().openSession();
DetachedCriteria dc = DetachedCriteria.forClass(MyEntity.class).add(Expression.idEq(id));
dc.setFetchMode("innerTable", FetchMode.JOIN);
Criteria c = dc.getExecutableCriteria(s);
MyEntity a = (MyEntity)c.uniqueResult();

Eso solo funcionaría para las relaciones ManyToOne y para ellas @ManyToOne(fetch=FetchType.EAGER) probablemente sería apropiado.

Se desaconseja y/o no funciona buscar más de una relación OneToMany, como se puede leer en el enlace que Jeremy publicó.Sólo piense en la declaración SQL que sería necesaria para realizar tal búsqueda...

Lo que he hecho es refactorizar el código para mantener un mapa de objetos para los administradores de entidades y cada vez que necesito actualizar, cerrar el antiguo administrador de entidades para el objeto y abrir uno nuevo.Utilicé la consulta anterior sin el buscar ya que eso es demasiado profundo para mis necesidades, simplemente haciendo una unión simple en las líneas de pedido, el buscar hace que sea aún más profundo.

Solo hay unos pocos objetos para los que necesito esto, alrededor de 20, por lo que creo que la sobrecarga de recursos al tener 20 administradores de entidades abiertos no es un problema, aunque los administradores de bases de datos pueden tener una visión diferente cuando esto se active...

También reelaboré cosas para que la base de datos funcione en el hilo principal y tenga el administrador de entidades.

cris

Si el problema es solo LazyInitializationExceptions, puede evitarlo agregando un OpenSessionInViewFilter.
Esto permitirá que los objetos se carguen en la vista, pero no ayudará con el problema de la velocidad.

     <filter>
        <filter-name>hibernateFilter</filter-name>
        <filter-class> org.springframework.orm.hibernate3.support.OpenSessionInViewFilter
        </filter-class>
    </filter>
    <filter-mapping>
        <filter-name>hibernateFilter</filter-name>
        <url-pattern>/*</url-pattern>
    </filter-mapping>
Licenciado bajo: CC-BY-SA con atribución
No afiliado a StackOverflow
scroll top