2010-02-08 5 views
1

J'ai un père (programme) avec une relation plusieurs-à-plusieurs avec leurs enfants (abonné). Le problème est lorsqu'il sérialise un programme, il sérialise également les abonnés du programme, ce qui implique de sérialiser leurs programmes, ce qui implique de sérialiser leurs abonnés, jusqu'à ce qu'il ait sérialisé chaque abonné & du programme dans la base de données.Sérialisation cyclique avec plusieurs à plusieurs relation avec Hibernate

Le ERD ressemble à: Programme < -> Abonné

Cela signifie ce qui était un petit bloc de 17KB des données (JSON) étant de retour est devenu un retour de 6.9MB. Ainsi, à son tour, souffle le temps de sérialiser les données et ensuite le renvoyer. Pourquoi mon parent retourne-t-il des enfants qui retournent chez des parents qui retournent des enfants? Comment puis-je arrêter cela afin que je reçoive seulement les abonnés pour chaque programme? Je suppose que j'ai fait quelque chose de mal avec mes annotations, peut-être? Je voudrais maintenir une relation plusieurs-à-plusieurs, mais sans cette récupération de données profondément imbriquée.

(Note:..? Je l'ai essayé avant d'ajouter autant de annotations Lazy je peux trouver juste pour voir si cela aide Cela ne peut-être pas, je fais ce mal aussi)

Program.java

@Entity 
@Table(name="programs") 
public class Program extends Core implements Serializable, Cloneable { 
    ... 
    @ManyToMany() 
    @JoinTable(name="program_subscribers", 
     joinColumns={@JoinColumn(name="program_uid")}, 
     inverseJoinColumns={@JoinColumn(name="subscriber_uid")}) 
    public Set<Subscriber> getSubscribers() { return subscribers; } 
    public void setSubscribers(Set<Subscriber> subscribers) { this.subscribers = subscribers; } 

Subscriber.java

@Entity 
@Table(name="subscribers") 
public class Subscriber extends Core implements Serializable { 
    ... 
    @ManyToMany(mappedBy="subscribers") 
    public Set<Program> getPrograms() { return programs; } 
    public void setPrograms(Set<Program> programs) { this.programs = programs; 

}

mise en œuvre

public Collection<Program> list() { 
    return new Programs.findAll(); 
} 

Répondre

-1

Bozho et ponkin sont sur la bonne voie. Je devais arrêter la sérialisation des données sur le réseau mais le gros problème est que je suis incapable de changer la classe/méthode pojo -> toJSON où la sérialisation a lieu. J'étais également inquiet d'investir du temps sur la méthode toJSON(), étant donné que je prenais un tel coup de performance au moment de la sérialisation, je voulais un correctif qui se produirait avant que j'ai eu les données plutôt que par la suite.

En raison de la nature du design bidirectionnel Many-to-Many que j'avais énuméré, j'allais toujours avoir ce problème de programmes cycliques/abonnés/programmes/.... Résolution: (pour l'instant atleast) J'ai supprimé la méthode Subscriber.getProgram() et créé une méthode finder sur ProgramDAO qui renvoie les programmes par abonné.

public List<Program> findBySubscriber(Subscriber subscriber) { 
    String hql = "select p " + 
    "from Program p " + 
    " join p.subscribers s " + 
    "where s = :sub" 
    ;  

    Query q = getSession().createQuery(hql); 
    q.setEntity("sub", subscriber); 

    List<Program> l = q.list(); 
    return l; 
} 

Pour tout travail CRUD Je pense que je vais juste devoir boucler sur Programs.getSubscribers ou écrire plus des méthodes d'aide HQL.

3

Vous n'avez pas mentionné le cadre que vous utilisez pour sérialisation JSON, donc je vais supposer JAXB. Quoi qu'il en soit, l'idée est de rendre transitoire le Subscriber.getPrograms(..), afin qu'il ne soit pas sérialisé. Hibernate prend soin de ces «boucles», mais d'autres ne le font pas. Donc:

@XmlTransient 
@ManyToMany(..) 
public Set<Program> getPrograms()... 

Si vous utilisez un autre cadre, il peut avoir une annotation/configuration différente pour spécifier les champs transitoires. Comme le mot-clé transient. L'autre façon est de personnaliser votre mapper pour gérer le cycle manuellement, mais c'est fastidieux.

+0

Il s'agit d'un projet à moi, je ne suis pas à 100% ce qui est utilisé pour la sérialisation JSON. Je vois des références à com.sdicons.json.mapper.JSONMapper.SimpleMapperHelper. Et nous avons une méthode publique JSONValue toJSON (Object pojo) throws MapperException {}. (devinez que cela roule votre propre sérialisation) –

+0

Aussi si j'annote getPrograms() @XmlTransient ceci signifierait que je pourrais ne jamais avoir les programmes d'abonné retournés? –

+0

oui. L'autre était de personnaliser votre mapper pour prendre soin du cycle manuellement. – Bozho

1

1) Comment fonctionne "votre" sérialisation. Je veux dire est-ce JAXB ou la sérialisation personnalisée ou smth autrement. 2) Presque tous les frameworks permettent de définir la profondeur de sérialisation. Je veux dire que vous pouvez définir par exemple la profondeur dans 2. 3) Je vous conseille de ne pas sérialiser l'objet avec les enfants, de les marquer (childre) transitoires et de sérialiser séparément.

Questions connexes