J'ai une entité qui contient:
@OneToMany(fetch = FetchType.EAGER, cascade = CascadeType.ALL, mappedBy = "assessment")
@OrderBy(value = "order ASC")
private List<AssessmentPart> assessmentParts = new LinkedList<>();
@OneToMany(fetch = FetchType.EAGER, cascade = CascadeType.ALL, mappedBy = "assessment")
private List<AssessmentText> texts = new LinkedList<>();
comme vous le voyez, il y a deux collections qui doivent être chargées avec impatience. Cela ne fonctionne pas et l'hibernation lève une exception:
Caused by: org.hibernate.loader.MultipleBagFetchException: cannot simultaneously fetch multiple bags
En effet, Hibernate ne peut pas récupérer plusieurs collections en une seule fois. Mais si je change le List
en Set
et le LinkedList
en HashSet
cette partie fonctionne bien mais l'autre - un problème plus ennuyeux se produit.
Lorsque j'essaye d'obtenir l'entité de la base de données en utilisant:
entityManager.find(entityClass, primaryKey);
Il échoue avec:
org.hibernate.AssertionFailure: null identifier
Je suis sûr que l'ID que je passe à la méthode find
n'est pas nul, j'ai débogué et j'en suis sûr. Il disparaît en quelque sorte à l'intérieur d'Hibernate.
Si je change les types de collection en LAZY
tout fonctionne sans erreur mais il y a des circonstances où j'ai besoin d'utiliser EAGER
.
Quelqu'un at-il une solution pour le réparer? Soit je pourrais avoir un ensemble mais empêcher une erreur d'assertion de se produire, soit je pourrais avoir une liste mais en quelque sorte éviter plusieurs erreurs de récupération de sacs.
J'utilise:
Hibernate 4.2.2.Final
Tomcat 7
JPA 2.0
JDK 1.7
MODIFIER
Je viens de découvrir que l'ajout de @Fetch(FetchMode.SELECT)
résout le problème et je peux utiliser plusieurs listes avec le type EAGER
, mais est-il possible de résoudre ce problème en n'utilisant pas d'annotations spécifiques à Hibernate? Et pourquoi cela a-t-il résolu le problème en premier lieu?
La cause première du problème est que lorsque Hibernate récupère les résultats de la requête SQL, il n'existe aucun moyen simple de dire quel élément enfant appartient à quelle collection. Voir cette entrée de blog pour une explication plus détaillée avec un exemple. Pour résumer, vous disposez des solutions de contournement suivantes:
@Fetch(FetchMode.SELECT)
@IndexColumn(name="LIST_INDEX")
Si vous utilisez Hibernate et que vous ne vous souciez pas d'utiliser les annotations Hibernate:
Annotez vos champs de collection avec:
@LazyCollection(LazyCollectionOption.FALSE)
N'oubliez pas de supprimer l'attribut fetchType de l'annotation @OneToMany.