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

java - manytoone - lazy hibernate example



Hibernate: mejor práctica para tirar de todas las colecciones perezosas (7)

Coloque el Utils.objectToJson (entidad); llamar antes del cierre de la sesión.

O puede intentar establecer el modo de búsqueda y jugar con un código como este

Session s = ... DetachedCriteria dc = DetachedCriteria.forClass(MyEntity.class).add(Expression.idEq(id)); dc.setFetchMode("innerTable", FetchMode.EAGER); Criteria c = dc.getExecutableCriteria(s); MyEntity a = (MyEntity)c.uniqueResult();

Lo que tengo:

@Entity public class MyEntity { @OneToMany(cascade = CascadeType.ALL, fetch = FetchType.LAZY, orphanRemoval = true) @JoinColumn(name = "myentiy_id") private List<Address> addreses; @OneToMany(cascade = CascadeType.ALL, fetch = FetchType.LAZY, orphanRemoval = true) @JoinColumn(name = "myentiy_id") private List<Person> persons; //.... } public void handle() { Session session = createNewSession(); MyEntity entity = (MyEntity) session.get(MyEntity.class, entityId); proceed(session); // FLUSH, COMMIT, CLOSE session! Utils.objectToJson(entity); //TROUBLES, because it can''t convert to json lazy collections }

Que problema:

El problema es que no puedo extraer la colección perezosa una vez cerrada la sesión. Pero tampoco puedo cerrar una sesión en el método de proceder .

Qué solución (solución gruesa):

a) Antes de cerrar la sesión, fuerce a hibernar para extraer colecciones perezosas

entity.getAddresses().size(); entity.getPersons().size();

....

b) Quizás una forma más elocuente es usar la @Fetch(FetchMode.SUBSELECT)

Pregunta:

¿Cuál es una mejor práctica / manera común / forma más elocuente de hacerlo? Significa convertir mi objeto a JSON.


Con Hibernate 4.1.6, se presenta una nueva característica para manejar esos problemas de asociación diferida. Cuando habilita la propiedad hibernate.enable_lazy_load_no_trans en hibernate.properties o en hibernate.cfg.xml, ya no tendrá LazyInitializationException.

Para obtener más información, consulte: https://.com/a/11913404/286588


Intente usar la biblioteca Gson para convertir objetos a Json

Ejemplo con servlets:

List<Party> parties = bean.getPartiesByIncidentId(incidentId); String json = ""; try { json = new Gson().toJson(parties); } catch (Exception ex) { ex.printStackTrace(); } response.setContentType("application/json"); response.setCharacterEncoding("UTF-8"); response.getWriter().write(json);


No es la mejor solución, pero esto es lo que obtuve:

1) Anota getter que quieres inicializar con esta anotación:

@Retention(RetentionPolicy.RUNTIME) public @interface Lazy { }

2) Use este método (se puede poner en una clase genérica, o puede cambiar T con la clase Object) en un objeto después de leerlo de la base de datos:

public <T> void forceLoadLazyCollections(T entity) { Session session = getSession().openSession(); Transaction tx = null; try { tx = session.beginTransaction(); session.refresh(entity); if (entity == null) { throw new RuntimeException("Entity is null!"); } for (Method m : entityClass.getMethods()) { Lazy annotation = m.getAnnotation(Lazy.class); if (annotation != null) { m.setAccessible(true); logger.debug(" method.invoke(obj, arg1, arg2,...); {} field", m.getName()); try { Hibernate.initialize(m.invoke(entity)); } catch (Exception e) { logger.warn("initialization exception", e); } } } } finally { session.close(); } }


Probablemente no se esté acercando a ninguna de las mejores prácticas, pero normalmente llamo SIZE en la colección para cargar a los niños en la misma transacción, como ha sugerido. Está limpio, es inmune a cualquier cambio en la estructura de los elementos secundarios y produce SQL con poca sobrecarga.


Puede atravesar Getters del objeto Hibernate en la misma transacción para asegurarse de que todos los objetos secundarios vagos se busquen ansiosamente con la siguiente clase de ayuda genérica :

HibernateUtil.initializeObject (myObject, "my.app.model");

package my.app.util; import java.lang.reflect.InvocationTargetException; import java.lang.reflect.Method; import java.util.HashSet; import java.util.Set; import org.aspectj.org.eclipse.jdt.core.dom.Modifier; import org.hibernate.Hibernate; public class HibernateUtil { public static byte[] hibernateCollectionPackage = "org.hibernate.collection".getBytes(); public static void initializeObject( Object o, String insidePackageName ) { Set<Object> seenObjects = new HashSet<Object>(); initializeObject( o, seenObjects, insidePackageName.getBytes() ); seenObjects = null; } private static void initializeObject( Object o, Set<Object> seenObjects, byte[] insidePackageName ) { seenObjects.add( o ); Method[] methods = o.getClass().getMethods(); for ( Method method : methods ) { String methodName = method.getName(); // check Getters exclusively if ( methodName.length() < 3 || !"get".equals( methodName.substring( 0, 3 ) ) ) continue; // Getters without parameters if ( method.getParameterTypes().length > 0 ) continue; int modifiers = method.getModifiers(); // Getters that are public if ( !Modifier.isPublic( modifiers ) ) continue; // but not static if ( Modifier.isStatic( modifiers ) ) continue; try { // Check result of the Getter Object r = method.invoke( o ); if ( r == null ) continue; // prevent cycles if ( seenObjects.contains( r ) ) continue; // ignore simple types, arrays und anonymous classes if ( !isIgnoredType( r.getClass() ) && !r.getClass().isPrimitive() && !r.getClass().isArray() && !r.getClass().isAnonymousClass() ) { // ignore classes out of the given package and out of the hibernate collection // package if ( !isClassInPackage( r.getClass(), insidePackageName ) && !isClassInPackage( r.getClass(), hibernateCollectionPackage ) ) { continue; } // initialize child object Hibernate.initialize( r ); // traverse over the child object initializeObject( r, seenObjects, insidePackageName ); } } catch ( InvocationTargetException e ) { e.printStackTrace(); return; } catch ( IllegalArgumentException e ) { e.printStackTrace(); return; } catch ( IllegalAccessException e ) { e.printStackTrace(); return; } } } private static final Set<Class<?>> IGNORED_TYPES = getIgnoredTypes(); private static boolean isIgnoredType( Class<?> clazz ) { return IGNORED_TYPES.contains( clazz ); } private static Set<Class<?>> getIgnoredTypes() { Set<Class<?>> ret = new HashSet<Class<?>>(); ret.add( Boolean.class ); ret.add( Character.class ); ret.add( Byte.class ); ret.add( Short.class ); ret.add( Integer.class ); ret.add( Long.class ); ret.add( Float.class ); ret.add( Double.class ); ret.add( Void.class ); ret.add( String.class ); ret.add( Class.class ); ret.add( Package.class ); return ret; } private static Boolean isClassInPackage( Class<?> clazz, byte[] insidePackageName ) { Package p = clazz.getPackage(); if ( p == null ) return null; byte[] packageName = p.getName().getBytes(); int lenP = packageName.length; int lenI = insidePackageName.length; if ( lenP < lenI ) return false; for ( int i = 0; i < lenI; i++ ) { if ( packageName[i] != insidePackageName[i] ) return false; } return true; } }


Use Hibernate.initialize() dentro de @Transactional para inicializar objetos perezosos.

start Transaction Hibernate.initialize(entity.getAddresses()); Hibernate.initialize(entity.getPersons()); end Transaction

Ahora, al lado de la Transacción, puede obtener objetos perezosos.

entity.getAddresses().size(); entity.getPersons().size();