C'est une question très courante, donc cette réponse est basée sur cet article que j'ai écrit sur mon blog.
Un à plusieurs
La relation de table un à plusieurs se présente comme suit:
Dans un système de base de données relationnelle, une relation de table un-à-plusieurs lie deux tables sur la base d'un Foreign Key
colonne de l'enfant qui fait référence à la ligne Primary Key
de la table parent.
Dans le diagramme de tableau ci-dessus, la post_id
colonne du post_comment
tableau a une Foreign Key
relation avec la colonne d' post
ID de table Primary Key
:
ALTER TABLE
post_comment
ADD CONSTRAINT
fk_post_comment_post_id
FOREIGN KEY (post_id) REFERENCES post
Annotation @ManyToOne
La meilleure façon de mapper la relation de table un à plusieurs consiste à utiliser @ManyToOne
annotation.
Dans notre cas, l'entité enfant PostComment
mappe la post_id
colonne de clé étrangère à l'aide de l' @ManyToOne
annotation:
@Entity(name = "PostComment")
@Table(name = "post_comment")
public class PostComment {
@Id
@GeneratedValue
private Long id;
private String review;
@ManyToOne(fetch = FetchType.LAZY)
private Post post;
}
Utilisation du JPA @OneToMany
annotation
Ce @OneToMany
n'est pas parce que vous avez la possibilité d'utiliser l' annotation que cela doit être l'option par défaut pour chaque un-à-plusieurs relation de base données . Le problème avec les collections est que nous ne pouvons les utiliser que lorsque le nombre d'enregistrements enfants est plutôt limité.
La meilleure façon de mapper une @OneToMany
association est de s'appuyer sur le @ManyToOne
côté pour propager tous les changements d'état d'entité:
@Entity(name = "Post")
@Table(name = "post")
public class Post {
@Id
@GeneratedValue
private Long id;
private String title;
@OneToMany(
mappedBy = "post",
cascade = CascadeType.ALL,
orphanRemoval = true
)
private List<PostComment> comments = new ArrayList<>();
//Constructors, getters and setters removed for brevity
public void addComment(PostComment comment) {
comments.add(comment);
comment.setPost(this);
}
public void removeComment(PostComment comment) {
comments.remove(comment);
comment.setPost(null);
}
}
L'entité parente,, Post
présente deux méthodes utilitaires (par exemple addComment
et removeComment
) qui sont utilisées pour synchroniser les deux côtés de l'association bidirectionnelle. Vous devez toujours fournir ces méthodes chaque fois que vous travaillez avec une association bidirectionnelle car, sinon, vous risquez des problèmes de propagation d'état très subtils .
L' @OneToMany
association unidirectionnelle est à éviter car elle est moins efficace que l'utilisation @ManyToOne
ou l' @OneToMany
association bidirectionnelle .
Pour plus de détails sur la meilleure façon de cartographier la @OneToMany
relation avec JPA et Hibernate, consultez cet article .
Un par un
La relation de table un-à-un se présente comme suit:
Dans un système de base de données relationnelle, une relation de table un-à-un lie deux tables en fonction d'une Primary Key
colonne de l'enfant qui fait également Foreign Key
référence à la ligne Primary Key
de la table parent.
Par conséquent, nous pouvons dire que la table enfant partage le Primary Key
avec la table parent.
Dans le diagramme ci-dessus, la id
colonne du post_details
tableau a également une Foreign Key
relation avec la colonne du post
tableau id
Primary Key
:
ALTER TABLE
post_details
ADD CONSTRAINT
fk_post_details_id
FOREIGN KEY (id) REFERENCES post
Utilisation de JPA @OneToOne
avec des @MapsId
annotations
La meilleure façon de cartographier une @OneToOne
relation est d'utiliser @MapsId
. De cette façon, vous n'avez même pas besoin d'une association bidirectionnelle puisque vous pouvez toujours récupérer l' PostDetails
entité en utilisant l' Post
identifiant d'entité.
Le mappage ressemble à ceci:
[code language = "java"] @Entity (name = "PostDetails") @Table (name = "post_details") classe publique PostDetails {
@Id
private Long id;
@Column(name = "created_on")
private Date createdOn;
@Column(name = "created_by")
private String createdBy;
@OneToOne(fetch = FetchType.LAZY)
@MapsId
@JoinColumn(name = "id")
private Post post;
public PostDetails() {}
public PostDetails(String createdBy) {
createdOn = new Date();
this.createdBy = createdBy;
}
//Getters and setters omitted for brevity
} [/ code]
De cette façon, la id
propriété sert à la fois de clé primaire et de clé étrangère. Vous remarquerez que la @Id
colonne n'utilise plus d' @GeneratedValue
annotation puisque l'identifiant est rempli avec l'identifiant de l' post
association.
Pour plus de détails sur la meilleure façon de cartographier la @OneToOne
relation avec JPA et Hibernate, consultez cet article .
Plusieurs à plusieurs
La relation de table plusieurs à plusieurs se présente comme suit:
Dans un système de base de données relationnelle, une relation de table plusieurs à plusieurs lie deux tables parentes via une table enfant qui contient deux Foreign Key
colonnes référençant les Primary Key
colonnes des deux tables parentes.
Dans le diagramme de tableau ci-dessus, la post_id
colonne du post_tag
tableau a également une Foreign Key
relation avec la colonne d' post
id de table Primary Key
:
ALTER TABLE
post_tag
ADD CONSTRAINT
fk_post_tag_post_id
FOREIGN KEY (post_id) REFERENCES post
Et, la tag_id
colonne de la post_tag
table a une Foreign Key
relation avec la colonne d' tag
ID de table Primary Key
:
ALTER TABLE
post_tag
ADD CONSTRAINT
fk_post_tag_tag_id
FOREIGN KEY (tag_id) REFERENCES tag
Utilisation du @ManyToMany
mappage JPA
Voici comment mapper la many-to-many
relation de table avec JPA et Hibernate:
@Entity(name = "Post")
@Table(name = "post")
public class Post {
@Id
@GeneratedValue
private Long id;
private String title;
@ManyToMany(cascade = {
CascadeType.PERSIST,
CascadeType.MERGE
})
@JoinTable(name = "post_tag",
joinColumns = @JoinColumn(name = "post_id"),
inverseJoinColumns = @JoinColumn(name = "tag_id")
)
private Set<Tag> tags = new HashSet<>();
//Getters and setters ommitted for brevity
public void addTag(Tag tag) {
tags.add(tag);
tag.getPosts().add(this);
}
public void removeTag(Tag tag) {
tags.remove(tag);
tag.getPosts().remove(this);
}
@Override
public boolean equals(Object o) {
if (this == o) return true;
if (!(o instanceof Post)) return false;
return id != null && id.equals(((Post) o).getId());
}
@Override
public int hashCode() {
return 31;
}
}
@Entity(name = "Tag")
@Table(name = "tag")
public class Tag {
@Id
@GeneratedValue
private Long id;
@NaturalId
private String name;
@ManyToMany(mappedBy = "tags")
private Set<Post> posts = new HashSet<>();
//Getters and setters ommitted for brevity
@Override
public boolean equals(Object o) {
if (this == o) return true;
if (o == null || getClass() != o.getClass()) return false;
Tag tag = (Tag) o;
return Objects.equals(name, tag.name);
}
@Override
public int hashCode() {
return Objects.hash(name);
}
}
- L'
tags
association dans l' Post
entité définit uniquement les types PERSIST
et MERGE
cascade. Comme expliqué dans cet article , la REMOVE
transition d'état d'entité n'a aucun sens pour une @ManyToMany
association JPA car elle pourrait déclencher une suppression de chaîne qui effacerait finalement les deux côtés de l'association.
- Comme expliqué dans cet article , les méthodes de l'utilitaire d'ajout / suppression sont obligatoires si vous utilisez des associations bidirectionnelles afin que vous puissiez vous assurer que les deux côtés de l'association sont synchronisés.
- L'
Post
entité utilise l'identificateur d'entité pour l'égalité car elle ne dispose d'aucune clé métier unique. Comme expliqué dans cet article , vous pouvez utiliser l'identificateur d'entité pour l'égalité tant que vous vous assurez qu'il reste cohérent dans toutes les transitions d'état d'entité .
- L'
Tag
entité possède une clé métier unique marquée de l' @NaturalId
annotation spécifique à Hibernate . Dans ce cas, la clé métier unique est le meilleur candidat pour les contrôles d'égalité .
- L'
mappedBy
attribut de l' posts
association dans l' Tag
entité marque que, dans cette relation bidirectionnelle, l' Post
entité est propriétaire de l'association. Cela est nécessaire car un seul côté peut posséder une relation et les modifications ne sont propagées à la base de données que de ce côté particulier.
- Il
Set
est préférable d'utiliser un List
avec @ManyToMany
est moins efficace.
Pour plus de détails sur la meilleure façon de cartographier la @ManyToMany
relation avec JPA et Hibernate, consultez cet article .