web-dev-qa-db-fra.com

Table JPA avec 2 champs de clé primaire

J'ai une table qui ne contient que 2 champs. La table a une PK composite formée par ces deux champs.

Lors de l'utilisation de Netbeans pour créer des beans entité à partir d'une base de données, le bean entité n'est pas créé automatiquement comme les autres tables comportant plus de 2 champs.

Je suppose donc que je dois créer le bean entité moi-même. Quelle est la meilleure pratique pour créer ce bean entité? Doit-il contenir un objet COMPOSITE KEY ou non?

11
user2046810

Je n'utilise pas NetBeans, je ne peux donc rien en dire sur ses outils de cartographie. 

Pour mapper une clé composite, il existe deux options. Vous pouvez 

  • Définissez un objet @Embeddable séparé avec les champs PK et utilisez-le comme @EmbeddedId dans votre classe @Entity

    @Embeddable
    public class MyCompositePK { 
        @Column
        private String fieldA;
        @Column
        private String fieldB;
    }
    @Entity 
    public class MyBean { 
        @EmbeddedId
        private MyCompositePK id;
        @Column
        private String fieldC;
    }
    
  • Définissez un POJO non mappé avec les champs PK et utilisez-le comme @IdClass dans le @Entity

    @Entity
    @IdClass(value=ClassAB.ClassABId.class)
    public class ClassAB implements Serializable {
        private String idA;
        private String idB;
    
        @Id
        @Column(name="ID_A")
        public String getIdA(){ return idA; }
        public void setIdA(String idA){ this.idA = idA; }
    
        @Id
        @Column(name="ID_B")
        public String getIdB(){ return idB; }
        public void setIdB(String idB){ this.idB = idB; }
    
        static class ClassABId implements Serializable {
            private String idA;
            private String idB;
    
            public String getIdA(){ return idA; }
            public void setIdA(String idA){ this.idA = idA; }
    
            public String getIdB(){ return idB; }
            public void setIdB(String idB){ this.idB = idB; }
    
            // implement equals(), hashcode()
        }
    }
    

    Dans cet exemple, ClassABId est une classe interne statique uniquement pour des raisons de commodité. 

Ces options sont également expliquées dans l'excellente réponse de Pascal Thivent à cette question: Comment mapper une clé composite avec Hibernate? .

Cette question connexe traite des différences entre ces approches: Quelle annotation dois-je utiliser: @IdClass ou @EmbeddedId . Notez que la déclaration des champs est dupliquée avec l'approche @IdClass

Quoi qu'il en soit, je ne pense pas qu'il existe une alternative à la création de deux classes. C'est pourquoi j'ai posé la question suivante: Mappage d'une classe composée uniquement d'une PK composite sans @IdClass ou @EmbeddedId . Il semble qu'il existe une fonctionnalité spécifique à l'hibernation pour cela.

Remarque: si vous avez le contrôle de la structure de la base de données, vous pouvez également envisager d'éviter les clés composites. Il y a quelques raisons de le faire .

28
Xavi López

Merci @ XaviLópez. Votre explication a corrigé mon code qui a été déclaré comme étant sa propre IdClass mentionnée par @Tom Anderson. Lorsque j'ai déclaré que sa propre classe IdClass avait 2 colonnes @ Id, une requête JPA extraire une liste de cette entité renvoyait les éléments "n" attendus dans la liste des résultats, mais chaque élément de cette liste est null. Mais cette taille "n" est attendue. Après être passé à la classe interne statique, ce qui est moins le refactoring, il est capable de retourner le bon jeu de résultats.

Selon moi: l'auto-référencement IdClass ne fonctionnera pas car le moi est déjà une entité et doit être en contexte de persistance. Si j'ai aussi un objet de clé primaire du même type, il y aura deux objets "identiques" dans le contexte de persistance. Donc, cela ne devrait pas être autorisé. Par conséquent, nous ne devrions pas utiliser l'auto-référencement @IdClass. Créez une classe interne statique en tant que type de clé primaire moins intrusive.

0
arunram