2009-12-12 8 views
3

J'ai une classe Hibernate qui est essentiellement juste une enveloppe autour de plusieurs collections.Rupture d'une grande classe Hibernate

Ainsi, la classe est (massivement simplifiée/pseudo) quelque chose comme:

 
@Entity 
public class MyClass { 

    @OneToMany 
    Map1 

    @OneToMany 
    Map2 

    @OneToMany 
    Map3 

    AddToMap1(); 
    AddToMap2(); 
    AddToMap3(); 
    RemoveFromMap1(); 
    RemoveFromMap2(); 
    RemoveFromMap3(); 
    DoWhateverWithMap1(); 
    DoWhateverWithMap2(); 
    DoWhateverWithMap3(); 

} 

etc. Chacune de ces Maps a alors quelques méthodes qui y sont associés (ajouter/supprimer/interroger/etc).

Comme vous pouvez l'imaginer, au moment où j'ai ajouté la 10e collection, la classe devient un peu ridicule en taille.

Ce que j'aimerais faire est quelque chose le long des lignes de:

 
@Entity 
public class MyClass { 

    ClassWrappingMap1; 

    ClassWrappingMap2; 

    ClassWrappingMap3; 
} 

Avec toutes les différentes méthodes enveloppées dans ces classes:

 
public class ClassWrappingMap1 { 

    @OneToMany 
    Map 

    AddToMap(); 
    RemoveFromMap(); 
    DoWhateverWithMap(); 

} 

Je pensais que je pourrais peut-être utiliser @Embedded pour cela, mais je ne semble pas pouvoir le faire fonctionner (Hibernate n'essaye même pas de maintenir la Map dans le wrapperClass).

Quelqu'un a déjà fait quelque chose comme ça avant? Des indices?

Un grand merci,
Ned

+1

Pouvez-vous montrer ce que vous avez essayé avec l'annotation @Embedded? –

+0

Bonne réponse. (+1) –

+0

Juha - J'ai fait exactement ce que votre code ("vous pourriez essayer quelque chose comme ça") ci-dessous. J'ai posté sur le forum Hibernate - Voyons voir si certains de ces gars peuvent décrire une meilleure pratique ou quelque chose. Merci beaucoup pour vos réponses. –

Répondre

2

Hibernate manual for annotations états suivants:

Bien que pas pris en charge par la spécification EJB3, Hibernate Annotations vous permet d'utiliser les annotations d'association dans un objet embarquable (ie @ * ToOne ou @*Trop). Pour remplacer les colonnes d'association, vous pouvez utiliser @AssociationOverride.

Votre approche d'emballage devrait donc fonctionner. Tout d'abord, vous devez vérifier tous les fichiers journaux, etc. pour toute erreur connexe.

Vous pouvez essayer quelque chose comme ceci:

  • Dans votre classe maître (MyClass)
 
@Entity 
public class MyClass { 

    @Embedded 
    ClassWrappingMap1 map1; 
} 
  • Et dans votre classe d'emballage
 
@Embeddable 
public class ClassWrappingMap1 { 

    @OneToMany 
    Map map1; 

} 

Notez que ClassWrappingMap1 utilise l'annotation @Embeddable. Cependant, selon docs, l'annotation @Embeddable ne devrait pas être nécessaire, elle devrait être utilisée par défaut lorsque l'annotation @Embedded est utilisée.

Assurez-vous que chaque classe ClassWrappingMap mappe une colonne différente dans la base de données. Les classes ClassWrappingMap ne doivent pas non plus avoir de clé primaire (colonnes @Id ou @EmbeddedId).

+0

Désolé mais Hibernate ne supporte pas @OneToMany lors de l'utilisation de @Embeddable. Vous avez vu ci-dessus "ni @ * ToMany" –

+0

Ouais, j'ai remarqué cela, mais je suppose que c'était une faute de frappe (puisque le contexte implique que c'est possible - "vous permet d'utiliser des annotations d'association dans un objet intégrable") "ou". Peut-être devrait-il dire "mais pas" plutôt que "ni". Je suppose que je pourrais sortir quelques classes auxiliaires contenant les méthodes, et laisser les @OneToManys dans la classe principale. Cela semble un peu douteux. D'autres suggestions? Merci Arthur et Juha d'avoir répondu. –

+0

Vous avez raison. Ça sonne mieux que "mais pas @ * ToMany" –

0

Bien que je ne connaisse pas de stratégie par défaut lors de l'utilisation d'une classe wrapper, vous pouvez utiliser un Hibernate Interceptor pour initialiser votre wrapper en remplaçant la méthode onLoad. Quelque chose comme

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; 
    } 
} 

prend en charge les éléments suivants:

Un client à l'aide intercepteur doit mettre en session propriété

donc votre code ressemble à celui

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

Ou utilisez Spring AOP pour faire la même tâche. Voir Domain Driven Design with Spring and Hibernate

Si vous connaissez une autre stratégie, partagez-la avec nous.

salutations,

+0

Arthur - Je pense que je vois où vous allez avec cette suggestion - mais si quelque chose rend la vie encore plus compliquée :-) Dans le pire des cas - Je peux mettre les collections @OneToMany dans la classe principale, puis passer une référence à une classe séparée contenant toutes les méthodes. Merci encore. –