Dans quel cas utilisez-vous l' @JoinTable
annotation JPA ?
Dans quel cas utilisez-vous l' @JoinTable
annotation JPA ?
Réponses:
EDIT 2017-04-29 : Comme l'ont souligné certains des commentateurs, l' JoinTable
exemple n'a pas besoin de l' mappedBy
attribut d'annotation. En fait, les versions récentes d'Hibernate refusent de démarrer en imprimant l'erreur suivante:
org.hibernate.AnnotationException:
Associations marked as mappedBy must not define database mappings
like @JoinTable or @JoinColumn
Supposons que vous ayez une entité nommée Project
et une autre entité nommée Task
et chaque projet peut avoir de nombreuses tâches.
Vous pouvez concevoir le schéma de base de données pour ce scénario de deux manières.
La première solution consiste à créer une table nommée Project
et une autre table nommée Task
et ajouter une colonne de clé étrangère à la table de tâches nommée project_id
:
Project Task
------- ----
id id
name name
project_id
De cette façon, il sera possible de déterminer le projet pour chaque ligne de la table des tâches. Si vous utilisez cette approche, dans vos classes d'entités, vous n'aurez pas besoin d'une table de jointure:
@Entity
public class Project {
@OneToMany(mappedBy = "project")
private Collection<Task> tasks;
}
@Entity
public class Task {
@ManyToOne
private Project project;
}
L'autre solution consiste à utiliser une troisième table, par exemple Project_Tasks
, et à stocker la relation entre les projets et les tâches dans cette table:
Project Task Project_Tasks
------- ---- -------------
id id project_id
name name task_id
La Project_Tasks
table est appelée "Join Table". Pour implémenter cette deuxième solution dans JPA, vous devez utiliser l' @JoinTable
annotation. Par exemple, pour implémenter une association un-à-plusieurs unidirectionnelle, nous pouvons définir nos entités comme telles:
Project
entité:
@Entity
public class Project {
@Id
@GeneratedValue
private Long pid;
private String name;
@JoinTable
@OneToMany
private List<Task> tasks;
public Long getPid() {
return pid;
}
public void setPid(Long pid) {
this.pid = pid;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public List<Task> getTasks() {
return tasks;
}
public void setTasks(List<Task> tasks) {
this.tasks = tasks;
}
}
Task
entité:
@Entity
public class Task {
@Id
@GeneratedValue
private Long tid;
private String name;
public Long getTid() {
return tid;
}
public void setTid(Long tid) {
this.tid = tid;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
}
Cela créera la structure de base de données suivante:
L' @JoinTable
annotation vous permet également de personnaliser divers aspects de la table de jointure. Par exemple, si nous avions annoté la tasks
propriété comme ceci:
@JoinTable(
name = "MY_JT",
joinColumns = @JoinColumn(
name = "PROJ_ID",
referencedColumnName = "PID"
),
inverseJoinColumns = @JoinColumn(
name = "TASK_ID",
referencedColumnName = "TID"
)
)
@OneToMany
private List<Task> tasks;
La base de données résultante serait devenue:
Enfin, si vous souhaitez créer un schéma pour une association plusieurs-à-plusieurs, l'utilisation d'une table de jointure est la seule solution disponible.
@JoinTable/@JoinColumn
peut être annoté sur le même champ avec mappedBy
. Ainsi , l'exemple devrait être correct garder le mappedBy
dans Project
et déplacez le @JoinColumn
vers Task.project
(ou vice-versa)
Project_Tasks
besoin de name
de Task
plus, qui devient trois colonnes: project_id
, task_id
, task_name
, comment y parvenir?
Caused by: org.hibernate.AnnotationException: Associations marked as mappedBy must not define database mappings like @JoinTable or @JoinColumn:
Il est également plus propre à utiliser @JoinTable
lorsqu'une entité peut être l'enfant dans plusieurs relations parent / enfant avec différents types de parents. Pour donner suite à l'exemple de Behrang, imaginez qu'une tâche peut être l'enfant d'un projet, d'une personne, d'un département, d'une étude et d'un processus.
La task
table doit -elle avoir 5 nullable
champs de clé étrangère? Je crois que non...
C'est la seule solution pour mapper une association ManyToMany: vous avez besoin d'une table de jointure entre les deux tables d'entités pour mapper l'association.
Il est également utilisé pour les associations OneToMany (généralement unidirectionnelles) lorsque vous ne souhaitez pas ajouter de clé étrangère dans la table du côté plusieurs et ainsi le garder indépendant du côté un.
Recherchez @JoinTable dans la documentation Hibernate pour obtenir des explications et des exemples.
Il vous permet de gérer la relation plusieurs à plusieurs. Exemple:
Table 1: post
post has following columns
____________________
| ID | DATE |
|_________|_________|
| | |
|_________|_________|
Table 2: user
user has the following columns:
____________________
| ID |NAME |
|_________|_________|
| | |
|_________|_________|
Join Table vous permet de créer un mappage en utilisant:
@JoinTable(
name="USER_POST",
joinColumns=@JoinColumn(name="USER_ID", referencedColumnName="ID"),
inverseJoinColumns=@JoinColumn(name="POST_ID", referencedColumnName="ID"))
créera une table:
____________________
| USER_ID| POST_ID |
|_________|_________|
| | |
|_________|_________|
@ManyToMany
les associationsLe plus souvent, vous devrez utiliser une @JoinTable
annotation pour spécifier le mappage d'une relation de table plusieurs à plusieurs:
Donc, en supposant que vous ayez les tables de base de données suivantes:
Dans l' Post
entité, vous mapperiez cette relation, comme ceci:
@ManyToMany(cascade = {
CascadeType.PERSIST,
CascadeType.MERGE
})
@JoinTable(
name = "post_tag",
joinColumns = @JoinColumn(name = "post_id"),
inverseJoinColumns = @JoinColumn(name = "tag_id")
)
private List<Tag> tags = new ArrayList<>();
L' @JoinTable
annotation est utilisée pour spécifier le nom de la table via l' name
attribut, ainsi que la colonne Clé étrangère qui fait référence à la post
table (par exemple, joinColumns
) et la colonne Clé étrangère dans la post_tag
table des liens qui fait référence à l' Tag
entité via l' inverseJoinColumns
attribut.
Notez que l'attribut cascade de l'
@ManyToMany
annotation est défini surPERSIST
etMERGE
uniquement parce que la mise en cascadeREMOVE
est une mauvaise idée puisque l'instruction DELETE sera émise pour l'autre enregistrement parent,tag
dans notre cas, pas pour l'post_tag
enregistrement. Pour plus de détails sur ce sujet, consultez cet article .
@OneToMany
Associations unidirectionnellesLes @OneToMany
associations unidirectionnelles , qui n'ont pas de @JoinColumn
mappage, se comportent comme des relations de table plusieurs-à-plusieurs, plutôt que comme des relations un-à-plusieurs.
Donc, en supposant que vous ayez les mappages d'entités suivants:
@Entity(name = "Post")
@Table(name = "post")
public class Post {
@Id
@GeneratedValue
private Long id;
private String title;
@OneToMany(
cascade = CascadeType.ALL,
orphanRemoval = true
)
private List<PostComment> comments = new ArrayList<>();
//Constructors, getters and setters removed for brevity
}
@Entity(name = "PostComment")
@Table(name = "post_comment")
public class PostComment {
@Id
@GeneratedValue
private Long id;
private String review;
//Constructors, getters and setters removed for brevity
}
Hibernate assumera le schéma de base de données suivant pour le mappage d'entités ci-dessus:
Comme déjà expliqué, le @OneToMany
mappage JPA unidirectionnel se comporte comme une association plusieurs-à-plusieurs.
Pour personnaliser la table des liens, vous pouvez également utiliser l' @JoinTable
annotation:
@OneToMany(
cascade = CascadeType.ALL,
orphanRemoval = true
)
@JoinTable(
name = "post_comment_ref",
joinColumns = @JoinColumn(name = "post_id"),
inverseJoinColumns = @JoinColumn(name = "post_comment_id")
)
private List<PostComment> comments = new ArrayList<>();
Et maintenant, la table de lien va être appelée post_comment_ref
et les colonnes de clé étrangère seront post_id
, pour la post
table, et post_comment_id
, pour la post_comment
table.
Les
@OneToMany
associations unidirectionnelles ne sont pas efficaces, il vaut donc mieux utiliser des@OneToMany
associations bidirectionnelles ou juste le@ManyToOne
côté. Consultez cet article pour plus de détails sur ce sujet.