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();