Rompere una vasta classe Hibernate
-
19-09-2019 - |
Domanda
Ho una classe Hibernate, che è essenzialmente un wrapper per i carichi di collezioni.
Quindi, la classe è (massicciamente semplificato / pseudo) qualcosa come:
@Entity public class MyClass { @OneToMany Map1 @OneToMany Map2 @OneToMany Map3 AddToMap1(); AddToMap2(); AddToMap3(); RemoveFromMap1(); RemoveFromMap2(); RemoveFromMap3(); DoWhateverWithMap1(); DoWhateverWithMap2(); DoWhateverWithMap3(); }
ecc. Ciascuna di queste mappe, allora ha un paio di metodi ad esso associati (aggiungere / rimuovere / interrogare / etc).
Come si può immaginare, per il momento ho aggiunto il 10 ° di raccolta o giù di lì, la classe è sempre un po 'ridicolo in termini di dimensioni.
Quello che mi piacerebbe fare è qualcosa sulla falsariga di:
@Entity public class MyClass { ClassWrappingMap1; ClassWrappingMap2; ClassWrappingMap3; }
Con tutti i vari metodi avvolto in tali classi:
public class ClassWrappingMap1 { @OneToMany Map AddToMap(); RemoveFromMap(); DoWhateverWithMap(); }
ho pensato che forse avrei potuto usare @Embedded
per questo, ma non mi sembra di essere in grado di farlo funzionare (Hibernate semplicemente non prova nemmeno a persistere la mappa all'interno della wrapperClass).
Qualcuno ha mai fatto qualcosa di simile prima? Eventuali suggerimenti?
Molte grazie,
Ned
Soluzione
Hibernate manuale per le annotazioni Stati seguente :
Anche se non supportato dalla specifica EJB3, Hibernate annotazioni consente di utilizzare le annotazioni di associazione in un oggetto embeddable (ad esempio @ * @ * TOONE né pressi di molte). Per ignorare le colonne di associazione è possibile utilizzare @AssociationOverride.
Quindi il vostro approccio avvolgente dovrebbe funzionare.
Prima di tutto, si deve controllare tutti i file di log, ecc per eventuali errori correlati.
Si potrebbe provare qualcosa di simile:
- Nella classe master (MyClass)
@Entity public class MyClass { @Embedded ClassWrappingMap1 map1; }
- E nella tua classe involucro
@Embeddable public class ClassWrappingMap1 { @OneToMany Map map1; }
Si noti che ClassWrappingMap1
utilizza annotazioni @Embeddable
. Tuttavia, secondo i documenti non dovrebbe essere necessario l'annotazione @Embeddable, dovrebbe essere di default quando si usa l'annotazione @Embedded.
Assicurarsi che ogni classe ClassWrappingMap associa una colonna diversa nel database. Anche le classi ClassWrappingMap non dovrebbero avere una chiave primaria (@Id
o colonne @EmbeddedId
).
Altri suggerimenti
Anche se non so una strategia di default quando si utilizza una classe wrapper, è possibile utilizzare un Hibernate Interceptor per inizializzare wrapper di sovrascrivendo onLoad metodo. Qualcosa di simile
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;
}
}
Si prende cura di quanto segue:
Un client che utilizza questo intercettore deve impostare la proprietà Session
Quindi, il codice sia come questo
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();
In alternativa, utilizzare Spring AOP per fare la stessa operazione. Vedere Domain Driven Design con la Primavera e Hibernate
Se si conosce un'altra strategia, condividerlo con noi.
saluti,