Quelle est la différence entre:
@Entity
public class Company {
@OneToMany(cascade = CascadeType.ALL , fetch = FetchType.LAZY)
@JoinColumn(name = "companyIdRef", referencedColumnName = "companyId")
private List<Branch> branches;
...
}
et
@Entity
public class Company {
@OneToMany(cascade = CascadeType.ALL , fetch = FetchType.LAZY, mappedBy = "companyIdRef")
private List<Branch> branches;
...
}
@JoinColumn
pourrait être utilisé des deux côtés de la relation. La question portait sur l’utilisation de @JoinColumn
sur @OneToMany
. côté (cas rare). Et le point ici est dans la duplication d'informations physiques (nom de colonne) avec requête SQL non optimisée qui produira des instructions UPDATE supplémentaires .
Selon documentation :
Depuis plusieurs à un sont (presque) toujours le côté propriétaire d'un relation bidirectionnelle dans la spécification JPA, l'association un à plusieurs est annotée par @OneToMany (mappedBy = ...)
@Entity
public class Troop {
@OneToMany(mappedBy="troop")
public Set<Soldier> getSoldiers() {
...
}
@Entity
public class Soldier {
@ManyToOne
@JoinColumn(name="troop_fk")
public Troop getTroop() {
...
}
Troop entretient une relation bidirectionnelle de un à plusieurs avec Soldier via la propriété de troupe. Vous n'avez pas (ne devez pas) définir de mappage physique du côté mappedBy.
Pour mapper un un vers plusieurs bidirectionnel, avec le côté propriétaire un comme plusieurs , vous devez supprimer l'élément mappedBy et définir le à un @JoinColumn insérable et modifiable à false. Cette solution n'est pas optimisée et produira des instructions UPDATE supplémentaires.
@Entity
public class Troop {
@OneToMany
@JoinColumn(name="troop_fk") //we need to duplicate the physical information
public Set<Soldier> getSoldiers() {
...
}
@Entity
public class Soldier {
@ManyToOne
@JoinColumn(name="troop_fk", insertable=false, updatable=false)
public Troop getTroop() {
...
}
L'annotation @JoinColumn
indique que cette entité est le propriétaire de la relation (c'est-à-dire que la table correspondante a une colonne avec une clé étrangère à la table référencée), tandis que l'attribut mappedBy
indique que l'entité de ce côté est l'inverse de la relation et que le propriétaire réside dans "l'autre" entité. Cela signifie également que vous pouvez accéder à l'autre table à partir de la classe annotée avec "mappedBy" (relation totalement bidirectionnelle).
En particulier, pour le code dans la question, les annotations correctes ressembleraient à ceci:
@Entity
public class Company {
@OneToMany(fetch = FetchType.LAZY, mappedBy = "company")
private List<Branch> branches;
}
@Entity
public class Branch {
@ManyToOne(fetch = FetchType.LAZY)
@JoinColumn(name = "companyId")
private Company company;
}
Comme je l'ai expliqué dans cet article , si vous utilisez l'annotation _@OneToMany
_ avec _@JoinColumn
_, vous disposez alors d'une association unidirectionnelle.
Si vous utilisez le _@OneToMany
_ avec le jeu d'attributs mappedBy
, vous avez une association bidirectionnelle, ce qui signifie que vous devez avoir une association _@ManyToOne
_ du côté enfant référée par le mappedBy
.
L’association nidirectionnel _@OneToMany
_ ne fonctionne pas très bien , vous devez donc l’éviter.
Il vaut mieux utiliser __ bidirectionnel _@OneToMany
_ qui est plus efficace .
L'annotation mappedBy devrait idéalement toujours être utilisée dans le côté parent (classe Société) de la relation bidirectionnelle, dans ce cas, il devrait être dans la classe Société pointant vers la variable membre 'société' de la classe Enfant. (Classe de branche)
L’annotation @ JoinColumn est utilisée pour spécifier une colonne mappée permettant de rejoindre une association d’entités. Cette annotation peut être utilisée dans n’importe quelle classe (parent ou enfant), mais elle devrait idéalement être utilisée uniquement dans un côté classe parent ou dans la classe Child pas dans les deux) ici dans ce cas je l'ai utilisé dans le côté enfant (classe Branch) de la relation bidirectionnelle indiquant la clé étrangère dans la classe Branch.
ci-dessous est l'exemple de travail:
classe mère, Société
@Entity
public class Company {
private int companyId;
private String companyName;
private List<Branch> branches;
@Id
@GeneratedValue
@Column(name="COMPANY_ID")
public int getCompanyId() {
return companyId;
}
public void setCompanyId(int companyId) {
this.companyId = companyId;
}
@Column(name="COMPANY_NAME")
public String getCompanyName() {
return companyName;
}
public void setCompanyName(String companyName) {
this.companyName = companyName;
}
@OneToMany(fetch=FetchType.LAZY,cascade=CascadeType.ALL,mappedBy="company")
public List<Branch> getBranches() {
return branches;
}
public void setBranches(List<Branch> branches) {
this.branches = branches;
}
}
classe enfant, branche
@Entity
public class Branch {
private int branchId;
private String branchName;
private Company company;
@Id
@GeneratedValue
@Column(name="BRANCH_ID")
public int getBranchId() {
return branchId;
}
public void setBranchId(int branchId) {
this.branchId = branchId;
}
@Column(name="BRANCH_NAME")
public String getBranchName() {
return branchName;
}
public void setBranchName(String branchName) {
this.branchName = branchName;
}
@ManyToOne(fetch=FetchType.LAZY)
@JoinColumn(name="COMPANY_ID")
public Company getCompany() {
return company;
}
public void setCompany(Company company) {
this.company = company;
}
}
Je voudrais juste ajouter que @JoinColumn
ne doit pas toujours être associé à l'emplacement de l'information physique comme this suggère. Vous pouvez combiner @JoinColumn
avec @OneToMany
même si la table parent n'a pas de données de table pointant vers la table enfant.
Comment définir une relation OneToMany unidirectionnelle dans JPA
OneToMany unidirectionnel, pas d'inverse ManyToOne, pas de table de jointure
Il ne semble être disponible que dans JPA 2.x+
bien que. C'est utile dans les situations où vous voulez que la classe enfant contienne uniquement l'ID du parent, pas une référence complète.
Je ne suis pas d'accord avec la réponse acceptée ici par Óscar López. Cette réponse est inexacte!
Ce n'est PAS @JoinColumn
qui indique que cette entité est le propriétaire de la relation. Au lieu de cela, c'est l'annotation @ManyToOne
qui le fait (dans son exemple).
Les annotations de relation telles que @ManyToOne
, @OneToMany
et @ManyToMany
indiquent à JPA/Hibernate to créer un mappage. Par défaut, cela se fait via une table de jointure séparée.
@ JoinColumn
Le but de
@JoinColumn
est de créer une colonne de jointure s'il n'en existe pas déjà une. Si tel est le cas, cette annotation peut être utilisée pour nommer la colonne de jointure.
MappedBy
Le paramètre
MappedBy
sert à indiquer à JPA: Ne créez PAS une autre table de jointure, car la relation est déjà mappée par l'entité opposée . de cette relation.
N'oubliez pas: MappedBy
est une propriété des annotations de relation dont le but est de générer un mécanisme permettant de mettre en relation deux entités qui, par défaut, créent une table de jointure. MappedBy
interrompt ce processus dans un sens.
L'entité n'utilisant pas MappedBy
est dite propriétaire de la relation car les mécanismes de la correspondance sont dictés dans sa classe par l'utilisation d'une des trois annotations de mappage avec le champ de clé étrangère. Cela spécifie non seulement la nature du mappage, mais indique également la création d'une table de jointure. En outre, l'option de suppression de la table de jointure existe également en appliquant l'annotation @JoinColumn sur la clé étrangère, qui la conserve à l'intérieur de la table de l'entité propriétaire.
En résumé: @JoinColumn
crée une nouvelle colonne de jointure ou renomme une colonne existante; tandis que le paramètre MappedBy
travaille en collaboration avec les annotations de relation de l'autre classe (enfant) afin de créer un mappage via une table de jointure ou en créant une colonne de clé étrangère dans la table associée de l'entité propriétaire.
Pour illustrer le fonctionnement de MapppedBy
, considérons le code ci-dessous. Si le paramètre MappedBy
devait être supprimé, Hibernate créerait en réalité DEUX tables de jointure! Pourquoi? Parce qu'il existe une symétrie dans les relations plusieurs à plusieurs et qu'Hibernate n'a aucune raison de choisir une direction plutôt qu'une autre.
Nous utilisons donc MappedBy
pour dire à Hibernate, nous avons choisi l'autre entité pour dicter le mappage de la relation entre les deux entités.
@Entity
public class Driver {
@ManyToMany(mappedBy = "drivers")
private List<Cars> cars;
}
@Entity
public class Cars {
@ManyToMany
private List<Drivers> drivers;
}
L'ajout de @JoinColumn (name = "driverID") à la classe de propriétaire (voir ci-dessous) empêchera la création d'une table de jointure et créera une colonne de clé étrangère driverID dans la table Cars pour construire un mappage:
@Entity
public class Driver {
@ManyToMany(mappedBy = "drivers")
private List<Cars> cars;
}
@Entity
public class Cars {
@ManyToMany
@JoinColumn(name = "driverID")
private List<Drivers> drivers;
}
JPA est une API en couches, les différents niveaux ont leurs propres annotations. Le niveau le plus élevé est le niveau (1) d'entité qui décrit les classes persistantes. Le niveau (2) de la base de données relationnelle suppose que les entités sont mappées sur une base de données relationnelle et (3) le modèle Java.
Annotations de niveau 1: @Entity, @Id, @OneToOne, @OneToMany, @ManyToOne, @ManyToMany. Vous pouvez introduire la persistance dans votre application en utilisant uniquement ces annotations de haut niveau. Mais vous devez ensuite créer votre base de données en fonction des hypothèses retenues par JPA. Ces annotations spécifient le modèle d'entité/relation.
Annotations de niveau 2: @Table, @Column, @JoinColumn, ... Influencez le mappage d'entités/propriétés sur les tables/colonnes de la base de données relationnelle si vous n'êtes pas satisfait des valeurs par défaut de JPA ou si vous devez mapper sur une base de données existante. Ces annotations peuvent être considérées comme des annotations d'implémentation. Elles spécifient comment le mappage doit être effectué.
À mon avis, il est préférable de coller autant que possible aux annotations de niveau supérieur, puis d'introduire les annotations de niveau inférieur en fonction des besoins.
Pour répondre aux questions: le @ OneToMany/mappedBy est le plus agréable car il utilise uniquement les annotations du domaine de l’entité. Le @ oneToMany/@ JoinColumn convient également, mais il utilise une annotation d'implémentation lorsque cela n'est pas strictement nécessaire.