web-dev-qa-db-fra.com

Récupérations multiples avec le type EAGER en veille prolongée avec JPA

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?

33
user2219247

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:

  • Chargez chaque collection séparément à l'aide de la sous-sélection @Fetch(FetchMode.SELECT)
  • Forcer l'utilisation de la liste au lieu du sac en ajoutant la colonne d'index @IndexColumn(name="LIST_INDEX")
  • Utilisez une collection non ordonnée comme Set.
60
Maksym Demidas

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.

15
willome