Romper una clase grande de hibernación
-
19-09-2019 - |
Pregunta
Tengo una clase de hibernación, que es esencialmente sólo una envoltura alrededor de un montón de colecciones.
Así es la clase (masivamente simplificada / pseudo) algo como:
@Entity public class MyClass { @OneToMany Map1 @OneToMany Map2 @OneToMany Map3 AddToMap1(); AddToMap2(); AddToMap3(); RemoveFromMap1(); RemoveFromMap2(); RemoveFromMap3(); DoWhateverWithMap1(); DoWhateverWithMap2(); DoWhateverWithMap3(); }
etc. Cada uno de esos mapas a continuación, tiene algunos métodos asociados a ella (añadir / eliminar / interrogar a / etc).
Como se puede imaginar, por el momento he añadido el 10 de recogida más o menos, la clase es cada vez un poco ridícula de tamaño.
Lo que me gustaría hacer es algo a lo largo de las líneas de:
@Entity public class MyClass { ClassWrappingMap1; ClassWrappingMap2; ClassWrappingMap3; }
Con todos los diversos métodos envueltos en esas clases:
public class ClassWrappingMap1 { @OneToMany Map AddToMap(); RemoveFromMap(); DoWhateverWithMap(); }
pensé que tal vez podría utilizar @Embedded
para esto, pero no parecen ser capaces de conseguir que funcione (Hibernate simplemente ni siquiera trata de persistir el mapa dentro de la wrapperClass).
¿Alguien ha hecho algo como esto antes? ¿Alguna pista?
Muchas gracias,
Ned
Solución
Hibernate manual para anotaciones estados siguientes :
Aunque no es soportado por la especificación EJB3, Anotaciones de Hibernate le permite utilizar las anotaciones de asociación en un objeto integrable (es decir, @ * Toone ni @ * ToMany). Para anular las columnas asociación puede utilizar @AssociationOverride.
Por lo que su enfoque de envoltura debería funcionar.
En primer lugar, usted debe comprobar todos los archivos de registro, etc de los errores relacionados.
Usted podría intentar algo como esto:
- En su clase magistral (MiClase)
@Entity public class MyClass { @Embedded ClassWrappingMap1 map1; }
- Y en su clase de envoltura
@Embeddable public class ClassWrappingMap1 { @OneToMany Map map1; }
Tenga en cuenta que ClassWrappingMap1
utiliza anotación @Embeddable
. Sin embargo, de acuerdo con documentos, no se necesita la anotación @Embeddable, debería ser por defecto cuando se usa la anotación @Embedded.
Asegúrese de que todas las clases ClassWrappingMap asigna una columna diferente en la base de datos. También clases ClassWrappingMap no deben tener una clave principal (o columnas @Id
@EmbeddedId
).
Otros consejos
A pesar de que no sé una estrategia por defecto cuando se utiliza una clase de contenedor, se puede utilizar un interceptor de Hibernate para inicializar su envoltura de reemplazando onLoad método. Algo así como
public class WrapperInterceptor extends EmptyInterceptor {
private Session session;
public boolean onLoad(Object entity, Serializable id, Object[] state, String[] propertyNames, Type[] types) {
if (entity instanceof MyClass) {
MyClass myClass = (MyClass) entity;
Query query = session.createQuery(<QUERY_TO_RETRIEVE_WRAPPED_ENTITY_GOES_HERE>);
WrappedEntity wrappedEntity = query.list().get(0);
myClass.setWrapperClass(new WrapperClass(wrappedEntity));
}
}
public void setSession(Session session) {
this.session = session;
}
}
se encarga de lo siguiente:
Un cliente que utiliza este interceptor debe establecer la propiedad de sesión
Así que el código tiene como éste
WrapperInterceptor interceptor = new WrapperInterceptor();
Session session = sessionFactory().openSession(interceptor);
Transaction tx = session.beginTransaction();
interceptor.setSession(session);
MyClass myClass = (MyClass) session.get(newItem, myClassId); // Triggers onLoad event
tx.commit();
session.close();
o usar un muelle AOP a hacer la misma tarea. Ver de dominio determinadas por el diseño con Spring e Hibernate
Si conoce otra estrategia, compartirlo con nosotros.
cordiales,