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?
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.
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.
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
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
où @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;
}
}
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
.
ne doit pas avoir de propriété @Id
lorsque @EmbeddedId
est utilisé.
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