Dans JPA, il existe un attribut appelé referencedColumnName
qui peuvent être réglées sur @JoinColumn, @PrimaryKeyJoinColumn
Quelle est l'idée derrière ce paramètre ? Quelqu'un peut-il donner un bon exemple d'utilisation ?
Réponses
Trop de publicités?La propriété "referencedColumnName" est le nom de la colonne de la table à laquelle vous faites référence avec la colonne que vous annotez. En d'autres termes, il s'agit de la colonne référencée dans la table de destination. Imaginez quelque chose comme ceci : des voitures et des personnes. Une personne peut avoir plusieurs voitures, mais une voiture n'appartient qu'à une seule personne (désolé, je n'aime pas que quelqu'un d'autre conduise ma voiture).
Personne de table
name char(64) primary key
âge intVoiture de table
car_registration char(32) primary key
marque_voiture (char 64)
modèle_de_voiture (char64)
owner_name char(64) foreign key references Personne(nom)
Lorsque vous mettez en œuvre des classes, vous aurez quelque chose comme
class Person{
...
}
class Car{
...
@ManyToOne
@JoinColumn([column]name="owner_name", referencedColumnName="name")
private Person owner;
}
EDIT : comme l'a fait remarquer @searchengine27, columnName
n'existe pas en tant que champ dans la section sur la persistance de la documentation Java7. Je ne me souviens plus où j'ai pris cette propriété, mais je me souviens l'avoir utilisée, c'est pourquoi je la laisse dans mon exemple.
Citation API sur referencedColumnName :
Le nom de la colonne référencée par cette clé étrangère colonne.
Défaut (ne s'applique que si sing Le même nom que la colonne de clé primaire de la table référencée.
Q/A
Où serait-il utilisé ?
Lorsqu'il y a un PK composite dans la table référencée vous devez alors spécifier le nom de la colonne à laquelle vous faites référence.
-
name
pointe sur la colonne contenant l'association, c'est-à-dire le nom de la colonne de la clé étrangère. -
referencedColumnName
pointe sur la colonne associée dans l'entité associée/référencée, c'est-à-dire le nom de la colonne de la clé primaire.
Vous n'êtes pas tenu de remplir le referencedColumnName
si l'entité référencée a une seule colonne comme PK, parce qu'il n'y a aucun doute sur la colonne à laquelle elle fait référence (c'est-à-dire la colonne Address
ID à colonne unique).
@ManyToOne
@JoinColumn(name="ADDR_ID")
public Address getAddress() { return address; }
Toutefois, si l'entité référencée a une PK qui s'étend sur plusieurs colonnes, l'ordre dans lequel vous indiquez @JoinColumn
a de l'importance. Il pourrait fonctionner sans les referencedColumnName
spécifié, mais c'est une question de chance. Vous devriez donc le cartographier de la manière suivante :
@ManyToOne
@JoinColumns({
@JoinColumn(name="ADDR_ID", referencedColumnName="ID"),
@JoinColumn(name="ADDR_ZIP", referencedColumnName="ZIP")
})
public Address getAddress() { return address; }
ou en cas de ManyToMany
:
@ManyToMany
@JoinTable(
name="CUST_ADDR",
joinColumns=
@JoinColumn(name="CUST_ID"),
inverseJoinColumns={
@JoinColumn(name="ADDR_ID", referencedColumnName="ID"),
@JoinColumn(name="ADDR_ZIP", referencedColumnName="ZIP")
}
)
Exemple concret
Deux requêtes générées par Hibernate à partir du même mappage de table de jointure, toutes deux sans colonne référencée spécifiée. Seul l'ordre de @JoinColumn
ont été modifiées.
/* load collection Client.emails */
select
emails0_.id_client as id1_18_1_,
emails0_.rev as rev18_1_,
emails0_.id_email as id3_1_,
email1_.id_email as id1_6_0_
from client_email emails0_
inner join email email1_ on emails0_.id_email=email1_.id_email
where emails0_.id_client='2' and
emails0_.rev='18'
/* load collection Client.emails */
select
emails0_.rev as rev18_1_,
emails0_.id_client as id2_18_1_,
emails0_.id_email as id3_1_,
email1_.id_email as id1_6_0_
from client_email emails0_
inner join email email1_ on emails0_.id_email=email1_.id_email
where emails0_.rev='2' and
emails0_.id_client='18'
Nous interrogeons une table de jointure pour obtenir les courriels des clients. La table {2, 18}
est l'identifiant composite du client. L'ordre des noms de colonnes est déterminé par l'ordre des colonnes @JoinColumn
annotations. L'ordre des deux entiers est toujours le même, probablement trié par hibernate et c'est pourquoi un alignement correct avec les colonnes de la table de jonction est nécessaire et nous ne pouvons pas ou ne devrions pas nous fier à l'ordre de mappage.
Ce qui est intéressant, c'est que l'ordre des nombres entiers ne correspond pas à l'ordre dans lequel ils sont représentés dans l'entité. {18, 2}
. Il semble donc qu'Hibernate trie les noms des colonnes avant de les utiliser dans la requête. Si c'est vrai et que vous voulez ordonner vos @JoinColumn
de la même manière que vous n'auriez pas besoin de referencedColumnName
mais je ne le dis qu'à titre d'illustration.
Remplissage adéquat referencedColumnName
permettent d'obtenir exactement la même requête sans l'ambiguïté, dans mon cas la deuxième requête ( rev = 2
, id_client = 18
).
Pour un exemple d'utilisation de JPA 2.x pour le cas général de deux tables, avec un @OneToMany
jointure unidirectionnelle voir https://en.wikibooks.org/wiki/Java_Persistence/OneToMany#Example_of_a_JPA_2.x_unidirectional_OneToMany_relationship_annotations
Capture d'écran de l'article JPA de WikiBooks : Exemple d'une base de données de relations unidirectionnelles OneToMany JPA 2.x