recursive manytoone lazyinitializationexception lazy initialize fetchtype false example java hibernate lazy-loading

java - manytoone - lazy hibernate example



TamaƱo de recopilaciĆ³n de recuento de Hibernate sin inicializar (3)

Puede usar Session # createFilter, que es una forma de HQL que opera explícitamente en colecciones. Por ejemplo, mencionas Padre e hijos así que si tienes una Persona p la forma más básica sería:

session.createFilter( p.getChildren(), "" ).list()

Esto simplemente le devuelve una lista de los niños. Es importante tener en cuenta que la colección devuelta no es "en vivo", de ninguna manera está asociada con p.

La parte interesante proviene del segundo argumento. Este es un fragmento HQL. Aquí, por ejemplo, es posible que desee:

session.createFilter( p.getChildren(), "select count(*)" ).uniqueResult();

Mencionó que tiene una cláusula where, por lo que también podría desear:

session.createFilter( p.getChildren(), "select count(*) where this.age > 18" ).uniqueResult();

Observe que no hay cláusula de. Es decir que la cláusula from está implícita en la asociación. A los elementos de la colección se les da el alias "this" para que pueda referirse a él desde otras partes del fragmento HQL.

¿Hay alguna forma de que pueda contar el tamaño de una colección asociada sin inicializar?

p.ej

Select count(p.children) from Parent p

(Hay una buena razón por la que no puedo hacer esto de otra manera, ya que mi cláusula where es más complicada y mi cláusula from es una consulta polimórfica)

Gracias.


Puedes hacer lo mismo así:

@Override public FaqQuestions getFaqQuestionById(Long questionId) { session = sessionFactory.openSession(); tx = session.beginTransaction(); FaqQuestions faqQuestions = null; try { faqQuestions = (FaqQuestions) session.get(FaqQuestions.class, questionId); Hibernate.initialize(faqQuestions.getFaqAnswers()); tx.commit(); faqQuestions.getFaqAnswers().size(); } finally { session.close(); } return faqQuestions; }

Simplemente use faqQuestions.getFaqAnswers (). Size () para su controlador y obtendrá el tamaño si la lista se actualiza de forma lenta, sin recuperar la lista.


Una posible solución distinta de las consultas podría estar mapeando los children con lazy="extra" (en notación XML). De esta forma, puede buscar a Parent en la consulta que necesite y luego llamar a parent.getChildren().size() sin cargar toda la colección (solo se ejecuta una consulta de tipo SELECT COUNT ).

Con las anotaciones, sería

@OneToMany @org.hibernate.annotations.LazyCollection( org.hibernate.annotations.LazyCollectionOption.EXTRA ) private Set<Child> children = new HashSet<Child>();

Actualización: Cita de Java Persistence con Hibernate , cap. 13.1.3:

Un proxy se inicializa si llama a cualquier método que no sea el método getter del identificador, una colección se inicializa si comienza a iterar a través de sus elementos o si llama a cualquiera de las operaciones de administración de colecciones, como size() y contains() . Hibernate proporciona una configuración adicional que es principalmente útil para grandes colecciones; se pueden mapear como extra perezosos . [...]

[Asignado como se indicó anteriormente], la colección ya no se inicializa si llama a size() , contains() o isEmpty() - se consulta la base de datos para recuperar la información necesaria. Si se trata de un Map o una List , las operaciones containsKey() y get() también consultan la base de datos directamente.

Entonces, con una entidad mapeada como arriba, puedes hacer

Parent p = // execute query to load desired parent // due to lazy loading, at this point p.children is a proxy object int count = p.getChildren().size(); // the collection is not loaded, only its size