Quelle annotation utiliser: @IdClass ou @EmbeddedId

la spécification JPA (Java Persistence API) comporte deux façons différentes de spécifier les clés composites des entités: @IdClass et @EmbeddedId .

j'utilise les deux annotations sur mes entités cartographiées, mais il s'avère que c'est un gros gâchis pour les gens qui ne sont pas très familiers avec JPA .

je veux adopter une seule façon de spécifier des clés composites. Qui est vraiment le meilleur? Pourquoi?

99
demandé sur Harshal Patil 2008-10-17 18:21:14

7 réponses

je considère que @EmbeddedId est probablement plus verbeux car avec @IdClass vous ne pouvez pas accéder à l'objet clé primaire entier en utilisant n'importe quel opérateur d'accès sur le terrain. En utilisant le @EmbeddedId vous pouvez faire comme ceci:

@Embeddable class EmployeeId { name, dataOfBirth }
@Entity class Employee {
  @EmbeddedId EmployeeId employeeId;
  ...
}

cela donne une notion claire des champs qui font la clé composite parce qu'ils sont tous agrégés dans une classe à laquelle on accède par l'intermédiaire d'un opérateur d'accès au champ.

autre différence avec @IdClass et @EmbeddedId est quand il s'agit d'écrire HQL:

avec @IdClass vous écrivez:

select e.name from Employee e

et avec @EmbeddedId vous devez écrire:

select e.employeeId.name from Employee e

Vous devez écrire plus de texte pour la même requête. Certains pourraient faire valoir que cela diffère d'un langage plus naturel comme celui promu par IdClass . Mais la plupart du temps comprendre droite à partir de la requête qu'un champ donné fait partie de la clé composite est de une aide précieuse.

72
répondu Jorge Ferreira 2014-10-01 11:35:41

j'ai découvert un cas où j'ai dû utiliser EmbeddedId au lieu de IdClass. Dans ce scénario il y a une table de jointure qui a des colonnes supplémentaires définies. J'ai essayé de résoudre ce problème en utilisant IdClass pour représenter la clé d'une entité qui représente explicitement des lignes dans la table de jointure. Je ne pouvais pas le faire fonctionner de cette façon. Heureusement "Java Persistence With Hibernate" a une section dédiée à ce sujet. Une solution proposée était très similaire à la mienne, mais il a utilisé EmbeddedId à la place. Je j'ai modelé mes objets sur ceux du livre.il se comporte maintenant correctement.

16
répondu laz 2014-12-09 19:49:19

il existe trois stratégies pour utiliser une clé primaire composée:

  • inscrivez @Embeddable et ajoutez à votre catégorie d'entités un bien normal pour elle, marqué @Id .
  • ajoutez à votre catégorie d'entités un bien normal pour elle, marqué @EmbeddedId .
  • ajoutez des propriétés à votre classe d'entités pour tous ses champs, marquez-les de @Id , et marquez votre classe d'entités de @IdClass , fournir la classe de votre classe de clé primaire.

l'utilisation de @Id avec une classe marquée comme @Embeddable est l'approche la plus naturelle. La balise @Embeddable peut être utilisée pour des valeurs non primaires. Il vous permet de traiter la clé primaire composée comme une propriété unique, et il permet la réutilisation de la classe @Embeddable dans d'autres tableaux.

la deuxième approche la plus naturelle est l'utilisation de l'étiquette @EmbeddedId . Ici, la classe de la clé primaire ne peut pas être utilisée dans d'autres tables puisqu'elle n'est pas une entité @Embeddable , mais elle nous permet de traiter la clé comme une seul attribut de classe.

enfin, l'utilisation des annotations @IdClass et @Id permet de cartographier la classe de la clé primaire composée en utilisant les propriétés de l'entité elle-même correspondant aux noms des propriétés de la classe de la clé primaire. Les noms doivent correspondre (il n'y a pas de mécanisme pour passer outre ceci), et la classe de la clé primaire doit respecter les mêmes obligations que pour les deux autres techniques. Le seul avantage de cette approche est sa capacité à "cacher" l'utilisation de la classe de la clé primaire de l'interface de l'entité enveloppante. L'annotation @IdClass prend un paramètre de valeur du type de classe, qui doit être la classe à utiliser comme clé primaire composée. Les champs qui correspondent aux propriétés de la classe de clé primaire à utiliser doivent tous être annotés avec @Id .

référence: http://www.apress.com/us/book/9781430228509

11
répondu Adelin 2017-07-25 13:05:59

autant que je sache, si votre composite PK contient FK, il est plus facile et plus simple d'utiliser @IdClass

avec @EmbeddedId vous devez définir la cartographie pour votre colonne FK deux fois, une fois dans @Embeddedable et une fois pour comme i.e. @ManyToOne@ManyToOne doit être lu en lecture seule ( @PrimaryKeyJoinColumn ) parce que vous ne pouvez pas avoir une colonne définie dans deux variables (conflits possibles).

Donc, vous devez configurer votre FK en utilisant le type simple dans @Embeddedable .

sur l'autre site en utilisant @IdClass cette situation peut être manipulée beaucoup plus facilement comme indiqué dans clés primaires à travers les relations OneToOne et ManyToOne :

exemple JPA 2.0 ManyToOne id annotation

...
@Entity
@IdClass(PhonePK.class)
public class Phone {

    @Id
    private String type;

    @ManyToOne
    @Id
    @JoinColumn(name="OWNER_ID", referencedColumnName="EMP_ID")
    private Employee owner;
    ...
}

exemple classe id JPA 2.0

...
public class PhonePK {
    private String type;
    private long owner;

    public PhonePK() {}

    public PhonePK(String type, long owner) {
        this.type = type;
        this.owner = owner;
    }

    public boolean equals(Object object) {
        if (object instanceof PhonePK) {
            PhonePK pk = (PhonePK)object;
            return type.equals(pk.type) && owner == pk.owner;
        } else {
            return false;
        }
    }

    public int hashCode() {
        return type.hashCode() + owner;
    }
}
11
répondu Ondrej Bozek 2018-02-02 14:02:02

je pense que le principal avantage est que nous pourrions utiliser @GeneratedValue pour l'id en utilisant le @IdClass ? Je suis sûr que nous ne pouvons pas utiliser @GeneratedValue pour @EmbeddedId .

6
répondu bertie 2014-12-10 08:22:42
La clé Composite

ne doit pas avoir de propriété @Id lorsque @EmbeddedId est utilisé.

4
répondu B.K 2014-12-10 08:23:05

avec EmbeddedId vous pouvez utiliser la clause dans HQL, par exemple: FROM Entity WHERE id IN :ids où id est un EmbeddedId alors qu'il est difficile d'atteindre le même résultat avec IdClass vous voudrez faire quelque chose comme FROM Entity WHERE idPartA = :idPartA0 AND idPartB = :idPartB0 .... OR idPartA = :idPartAN AND idPartB = :idPartBN

0
répondu Aleks Ben Maza 2018-04-02 17:20:35