web-dev-qa-db-fra.com

L'héritage JPA @EntityGraph inclut des associations facultatives de sous-classes

Étant donné le modèle de domaine suivant, je veux charger tous les Answer, y compris leurs Value et leurs sous-enfants respectifs, et les placer dans un AnswerDTO pour ensuite les convertir en JSON. J'ai une solution fonctionnelle mais elle souffre du problème N + 1 dont je veux me débarrasser en utilisant un @EntityGraph. Toutes les associations sont configurées LAZY.

enter image description here

@Query("SELECT a FROM Answer a")
@EntityGraph(attributePaths = {"value"})
public List<Answer> findAll();

Utilisation d'un @EntityGraph sur la méthode Repository Je peux m'assurer que les valeurs sont pré-extraites pour empêcher N + 1 sur le Answer->Value association. Bien que mon résultat soit correct, il y a un autre problème N + 1, à cause du chargement paresseux de l'association selected des MCValues.

Utiliser ceci

@EntityGraph(attributePaths = {"value.selected"})

échoue, car le champ selected n'est bien sûr qu'une partie de certaines des entités Value:

Unable to locate Attribute  with the the given name [selected] on this ManagedType [x.model.Value];

Comment puis-je dire à JPA d'essayer de récupérer uniquement l'association selected au cas où la valeur serait un MCValue? J'ai besoin de quelque chose comme optionalAttributePaths.

17
Stuck

Modifié après votre commentaire:

Je m'excuse, je n'ai pas compris votre problème au premier tour, votre problème se produit au démarrage de spring-data, pas seulement lorsque vous essayez d'appeler findAll ().

Ainsi, vous pouvez maintenant naviguer dans l'exemple complet qui peut être extrait de mon github: https://github.com/bdzzaid/stackoverflow-Java/blob/master/jpa-hibernate/

Vous pouvez facilement reproduire et résoudre votre problème dans ce projet.

En effet, les données Spring et la mise en veille prolongée ne sont pas capables de déterminer le graphique "sélectionné" par défaut et vous devez spécifier la manière de collecter l'option sélectionnée.

Donc d'abord, vous devez déclarer les NamedEntityGraphs de la classe Answer

Comme vous pouvez le voir, il y a deux NamedEntityGraph pour l'attribut value de la classe Réponse

  • Le premier pour tous Valeur sans relation spécifique à charger

  • Le second pour la valeur spécifique Multichoice . Si vous supprimez celui-ci, vous reproduisez l'exception.

Deuxièmement, vous devez être dans un contexte transactionnel answerRepository.findAll () si vous souhaitez récupérer des données de type [~ # ~] paresseux [~ # ~]

@Entity
@Table(name = "answer")
@NamedEntityGraphs({
    @NamedEntityGraph(
            name = "graph.Answer", 
            attributeNodes = @NamedAttributeNode(value = "value")
    ),
    @NamedEntityGraph(
            name = "graph.AnswerMultichoice",
            attributeNodes = @NamedAttributeNode(value = "value"),
            subgraphs = {
                    @NamedSubgraph(
                            name = "graph.AnswerMultichoice.selected",
                            attributeNodes = {
                                    @NamedAttributeNode("selected")
                            }
                    )
            }
    )
}
)
public class Answer
{

    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    @Column(updatable = false, nullable = false)
    private int id;

    @OneToOne(cascade = CascadeType.ALL)
    @JoinColumn(name = "value_id", referencedColumnName = "id")
    private Value value;
// ..
}
0
bdzzaid