2010-06-29 5 views
5

Je suis en train de déplacer une application (de travail) d'EclipseLink à Hibernate JPA, la plupart du temps ça marche très bien, mais je trouve une chose que je ne peux pas expliquer, et je peux aussi Ne pensez pas à de bons termes de recherche!Hibernate JPA - Relation ManyToOne non renseignée

Fondamentalement, j'ai quatre entités, avec un à-plusieurs formant une chaîne:

l'Entité a une liste de l'Entité de, dont chacun a une liste de EntityC de, chacun d'avoir une liste des EntityD de

chacun de ceux qui étaient alors a un beaucoup à une relation l'autre sens, si:

EntityD a une EntityC, qui a une Entité B, qui a une Entité a.

qui est (fortement réduite pour plus de clarté):

@Entity 
public class EntityA { 
    @OneToMany (cascade = CascadeType.All, mappedBy = "entityA") 
    private List<EntityB> entityBList; 
    ... 
} 

@Entity 
public class EntityB { 
    @OneToMany (cascade = CascadeType.All, mappedBy = "entityB") 
    private List<EntityC> entityCList; 

    @JoinColumn (name = "ENTITY_A", referencedColumnName = "ENTITY_A_ID") 
    @ManyToOne (cascade = CascadeType.PERSIST, optional = false) 
    private EntityA entityA; 
} 

@Entity 
public class EntityC { 
    @OneToMany (cascade = CascadeType.ALL, mappedBy = "entityC") 
    private List<EntityD> entityDList; 

    @JoinColumn (name = "ENTITY_B", referencedColumnName = "ENTITY_B_ID") 
    @ManyToOne (cascade = CascadeType.PERSIST, optional = false) 
    private EntityB entityB; 
} 

@Entity 
public class EntityD { 
    @JoinColumn (name = "ENTITY_C", referencedColumnName = "ENTITY_C_ID") 
    @ManyToOne (cascade = CascadeType.PERSIST, optional = false) 
    private EntityC entityC; 
} 

je reçois une Entité A partir de la base de données (le regardant par sa clé primaire), et ainsi obtenir une instance l'Entité bien peuplée, avec un PersistentBag pour mon List<EntityB>. Je vois une charge paresseuse se produire lorsque je déréférence que List<EntityB>, et le même répété pour obtenir EntityCs de EntityB. À ce stade, tout est comme je m'attends, j'ai une EntityA, B et C entièrement rempli avec les valeurs de la base de données, mais ensuite j'essaye d'obtenir mon EntityD, à partir d'EntityC, et trouve que c'est null.

Mon gestionnaire d'entités est toujours ouvert et actif à ce stade, et même si je le regarde dans le débogueur immédiatement après avoir obtenu l'EntityA, je peux parcourir les relations, jusqu'à EntityC, et voir à nouveau le 'entityDList 'comme nul.

La seule solution que j'ai trouvé à ce jour est d'utiliser:

EntityManager.refresh(entityC); 

qui remplit tous ses éléments, y compris un PersistentBag paresseusement chargé pour le entityDList. Donc, à mon avis, Hibernate ne remplit que les références de 2 niveaux de profondeur (ou 3, selon la façon dont vous comptez), et abandonne par la suite, bien que je ne comprenne pas vraiment pourquoi. Cela a-t-il du sens pour qui que ce soit?

Existe-t-il une autre solution que le .refresh? Une sorte de valeur de config ou d'annotation qui fera que Hibernate peuplera les références tout le long?

+0

Quelle est la valeur définie pour le paramètre de configuration d'hibernation "max_fetch_depth"? –

Répondre

2

Grâce aux suggestions de personnes ici, qui sont probablement pertinentes, mais qui n'ont pas aidé mon cas spécifique.Si vous rencontrez le même problème, cela vaut probablement la peine d'essayer la suggestion de max_fetch_depth, mais pour une raison quelconque, cela n'a pas fonctionné pour moi (j'aimerais savoir pourquoi?). De même, si vos @ OneToMany sont des Sets, plutôt que des Lists, faire une recherche hâtive ou une jointure à gauche, comme suggéré par Albert, mais apparemment Hibernate ne vous permet que d'avoir un maximum de 1 Liste très recherchée, Si vous avez besoin de plus, vos collections doivent être des ensembles. Je n'ai pas essayé, mais je soupçonne que cela aurait pu résoudre le problème.

À moins que quelqu'un ait une meilleure suggestion, je m'en tiendrai à l'appel d'actualisation, ce qui est probablement plus logique pour mon application.

1

C'est drôle en effet. Une façon de contourner ce problème serait d'interroger l'objet A vers la gauche pour aller chercher -> B-> C-> D, ce qui est également plus rapide si vous allez de toute façon traverser vers l'objet D. Ce serait quelque chose comme ça.

"from A left join fetch B left join fetch C left join fetch D" 

Avez-vous également essayé de faire la relation avec C-> D désireux? Curieux ce qui se passera alors ...

+0

Merci Albert, j'ai essayé les deux suggestions, en vain :(Faire la relation désireux n'avait aucun effet, alors j'ai essayé de faire toutes les 3 relations (A-> B-> C-> D) désireux, mais Hibernate se plaint de "ne peut pas simultanément J'ai trouvé quelque chose ailleurs, suggérant que c'est parce que les collections que je cherche avec impatience sont des listes, et que cela fonctionnerait si je les fabriquais, mais Je suis trop paresseux pour le faire maintenant, donc je pense que je vais juste mettre en place un appel de rafraîchissement! – DaveyDaveDave

1

Les docs hibernate disent que vous pouvez le définir avec la propriété hibernate.max_fetch_depth. La valeur par défaut est 3. Vous pouvez la trouver dans le "Hibernate Reference Documentation" à la page 47.

+0

Merci pour cela - savez-vous si le fichier hibernate.properties est également utilisé par Hibernate JPA, je ne trouve pas une réponse n'importe où dans les docs Hibernate? J'ai essayé de le changer à 4 et aussi 0, et il semble n'avoir aucun effet ... – DaveyDaveDave

+0

OK, ignorer le ci-dessus, il semble être utilisé, car en définissant max_fetch_depth à 0 a cassé d'autres parties de mon application :) Le réglage à un nombre élevé si (j'ai essayé 4 et 10), ne semble pas avoir d'effet; Je suppose que c'est juste un maximum, et quelque chose d'autre persuade Hibernate de s'arrêter à 3 niveaux ...? – DaveyDaveDave

Questions connexes