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 associe deux tables sur la base d'une Foreign Key
dans la table enfant qui fait référence à la colonne Primary Key
d'un enregistrement dans la table parent.
Dans le diagramme du tableau ci-dessus, le post_id
dans la colonne post_comment
Le tableau a une Foreign Key
la relation avec le post
table id Primary Key
colonne :
ALTER TABLE
post_comment
ADD CONSTRAINT
fk_post_comment_post_id
FOREIGN KEY (post_id) REFERENCES post
Annotation @ManyToOne
En JPA, la meilleure façon de représenter la relation de table un-à-plusieurs est d'utiliser l'attribut @ManyToOne
annotation.
Dans notre cas, le PostComment
met en correspondance l'entité enfant post_id
colonne de clé étrangère à l'aide de l'option @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 de l'APP @OneToMany
annotation
Ce n'est pas parce que vous avez la possibilité d'utiliser le @OneToMany
cela ne signifie pas qu'elle doit être l'option par défaut pour toutes les annotations de l un à plusieurs les relations entre les bases de données.
Le problème des collections JPA est qu'elles ne peuvent être utilisées que lorsque le nombre d'éléments est assez faible.
La meilleure façon de cartographier un @OneToMany
est de s'appuyer sur la @ManyToOne
pour propager tous les changements d'état de l'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);
}
}
Le parent Post
comporte deux méthodes utilitaires (par exemple addComment
y removeComment
) qui sont utilisés pour synchroniser les deux côtés de l'association bidirectionnelle.
Vous devez fournir ces méthodes chaque fois que vous travaillez avec une association bidirectionnelle. problèmes très subtils de propagation de l'état .
Le système unidirectionnel @OneToMany
est à éviter car elle est moins efficace que l'utilisation de l'association @ManyToOne
ou l'option bidirectionnelle @OneToMany
association.
Un à un
La relation univoque entre les tables se présente comme suit :
Dans un système de base de données relationnelle, une relation de table univoque relie deux tables sur la base d'une Primary Key
dans l'enfant qui est également un Foreign Key
renvoyant à la Primary Key
de la ligne du tableau parent.
Par conséquent, nous pouvons dire que la table enfant partage la Primary Key
avec le tableau parent.
Dans le diagramme du tableau ci-dessus, le id
dans la colonne post_details
a également un Foreign Key
la relation avec le post
table id
Primary Key
colonne :
ALTER TABLE
post_details
ADD CONSTRAINT
fk_post_details_id
FOREIGN KEY (id) REFERENCES post
Utilisation de l'APP @OneToOne
avec @MapsId
annotations
La meilleure façon de cartographier un @OneToOne
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 le fichier PostDetails
en utilisant l'option Post
identifiant de l'entité.
La cartographie se présente comme suit :
@Entity(name = "PostDetails")
@Table(name = "post_details")
public class 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
}
De cette manière, le id
sert à la fois de clé primaire et de clé étrangère. Vous remarquerez que la propriété @Id
n'utilise plus de colonne @GeneratedValue
puisque l'identifiant est complété par l'identifiant de l'élément post
l'association.
Plusieurs à plusieurs
La relation de table de plusieurs à plusieurs se présente comme suit :
Dans un système de base de données relationnelle, une relation de table de plusieurs à plusieurs relie deux tables mères par l'intermédiaire d'une table fille qui contient deux tables. Foreign Key
les colonnes qui font référence à la Primary Key
des deux tables mères.
Dans le diagramme du tableau ci-dessus, le post_id
dans la colonne post_tag
a également un Foreign Key
la relation avec le post
table id Primary Key
colonne :
ALTER TABLE
post_tag
ADD CONSTRAINT
fk_post_tag_post_id
FOREIGN KEY (post_id) REFERENCES post
Et, le tag_id
dans la colonne post_tag
Le tableau a une Foreign Key
la relation avec le tag
table id Primary Key
colonne :
ALTER TABLE
post_tag
ADD CONSTRAINT
fk_post_tag_tag_id
FOREIGN KEY (tag_id) REFERENCES tag
Utilisation de l'APP @ManyToMany
cartographie
C'est ainsi que vous pouvez mapper le many-to-many
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 getClass().hashCode();
}
}
@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);
}
}
- Les
tags
dans l'association Post
ne définit que l'entité PERSIST
y MERGE
les types de cascades. Les REMOVE
La transition d'état d'une entité n'a pas de sens pour un @ManyToMany
JPA, car cela pourrait déclencher une suppression de chaîne qui finirait par effacer les deux parties de l'association.
- Les méthodes utilitaires d'ajout/suppression sont obligatoires si vous utilisez des associations bidirectionnelles afin de vous assurer que les deux parties de l'association sont synchronisées.
- Les
Post
utilise l'identifiant de l'entité à des fins d'égalité, car elle ne dispose pas d'une clé de gestion unique. Vous pouvez utiliser l'identifiant de l'entité pour l'égalité à condition de vous assurer qu'il reste cohérent dans toutes les transitions d'état de l'entité.
- Les
Tag
possède une clé de gestion unique qui est marquée par la clé de gestion spécifique à Hibernate @NaturalId
annotation. Lorsque c'est le cas, la clé unique de l'entreprise est le meilleur candidat pour les contrôles d'égalité .
- Les
mappedBy
de l'attribut posts
dans l'association Tag
marque que, dans cette relation bidirectionnelle, l'entité Post
est propriétaire de l'association. Cela est nécessaire car une relation ne peut appartenir qu'à une seule partie et les modifications ne sont propagées dans la base de données qu'à partir de cette partie particulière.
- Les
Set
est à privilégier, car l'utilisation d'un List
avec @ManyToMany
est moins efficace.