Ini adalah pertanyaan yang sangat umum, jadi jawaban ini didasarkan pada artikel yang saya tulis di blog saya.
Satu-ke-banyak
Hubungan tabel satu-ke-banyak terlihat sebagai berikut:
Dalam sistem database relasional, hubungan tabel satu-ke-banyak menghubungkan dua tabel berdasarkan Foreign Key
kolom pada anak yang merujuk pada Primary Key
baris tabel induk.
Dalam diagram tabel di atas, post_id
kolom dalam post_comment
tabel memiliki Foreign Key
hubungan dengan kolom post
id tabel Primary Key
:
ALTER TABLE
post_comment
ADD CONSTRAINT
fk_post_comment_post_id
FOREIGN KEY (post_id) REFERENCES post
@ManyToOne penjelasan
Cara terbaik untuk memetakan hubungan tabel satu-ke-banyak adalah dengan menggunakan @ManyToOne
anotasi.
Dalam kasus kami, entitas anak, PostComment
memetakan post_id
kolom Kunci Asing menggunakan @ManyToOne
anotasi:
@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;
}
Menggunakan @OneToMany
anotasi JPA
Hanya karena Anda memiliki opsi untuk menggunakan @OneToMany
anotasi, itu tidak berarti ini harus menjadi opsi default untuk setiap hubungan database satu-ke-banyak . Masalah dengan koleksi adalah bahwa kita hanya bisa menggunakannya ketika jumlah catatan anak agak terbatas.
Cara terbaik untuk memetakan @OneToMany
asosiasi adalah dengan mengandalkan @ManyToOne
sisi untuk menyebarkan semua perubahan status entitas:
@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);
}
}
Entitas induk Post
,, menampilkan dua metode utilitas (misalnya addComment
dan removeComment
) yang digunakan untuk menyinkronkan kedua sisi dari asosiasi dua arah. Anda harus selalu memberikan metode ini setiap kali Anda bekerja dengan asosiasi dua arah karena, jika tidak, Anda berisiko mengalami masalah propagasi negara yang sangat halus .
@OneToMany
Asosiasi searah harus dihindari karena kurang efisien daripada menggunakan @ManyToOne
atau @OneToMany
asosiasi dua arah .
Untuk detail lebih lanjut tentang cara terbaik untuk memetakan @OneToMany
hubungan dengan JPA dan Hibernate, lihat artikel ini .
Satu-ke-satu
Hubungan tabel satu-ke-satu terlihat sebagai berikut:
Dalam sistem basis data relasional, hubungan tabel satu-ke-satu menghubungkan dua tabel berdasarkan Primary Key
kolom pada anak yang juga merupakan Foreign Key
referensi Primary Key
dari baris tabel induk.
Oleh karena itu, kita dapat mengatakan bahwa tabel anak berbagi Primary Key
dengan tabel induk.
Dalam diagram tabel di atas, id
kolom dalam post_details
tabel juga memiliki Foreign Key
hubungan dengan kolom post
tabel id
Primary Key
:
ALTER TABLE
post_details
ADD CONSTRAINT
fk_post_details_id
FOREIGN KEY (id) REFERENCES post
Menggunakan JPA @OneToOne
dengan @MapsId
anotasi
Cara terbaik untuk memetakan @OneToOne
hubungan adalah menggunakan @MapsId
. Dengan cara ini, Anda bahkan tidak memerlukan asosiasi dua arah karena Anda selalu dapat mengambil PostDetails
entitas dengan menggunakan Post
pengidentifikasi entitas.
Pemetaannya terlihat seperti ini:
[kode bahasa = "java"] @Entity (name = "PostDetails") @Table (name = "post_details") kelas publik 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
} [/ kode]
Dengan cara ini, id
properti berfungsi sebagai Primary Key dan Foreign Key. Anda akan melihat bahwa @Id
kolom tidak lagi menggunakan @GeneratedValue
anotasi karena pengenal diisi dengan pengidentifikasi post
asosiasi.
Untuk detail lebih lanjut tentang cara terbaik untuk memetakan @OneToOne
hubungan dengan JPA dan Hibernate, lihat artikel ini .
Banyak ke banyak
Hubungan tabel banyak-ke-banyak terlihat sebagai berikut:
Dalam sistem basis data relasional, hubungan banyak-ke-banyak tabel menghubungkan dua tabel induk melalui tabel anak yang berisi dua Foreign Key
kolom referensi Primary Key
kolom dari dua tabel induk.
Dalam diagram tabel di atas, post_id
kolom dalam post_tag
tabel juga memiliki Foreign Key
hubungan dengan kolom post
id tabel Primary Key
:
ALTER TABLE
post_tag
ADD CONSTRAINT
fk_post_tag_post_id
FOREIGN KEY (post_id) REFERENCES post
Dan, tag_id
kolom dalam post_tag
tabel memiliki Foreign Key
hubungan dengan kolom tag
id tabel Primary Key
:
ALTER TABLE
post_tag
ADD CONSTRAINT
fk_post_tag_tag_id
FOREIGN KEY (tag_id) REFERENCES tag
Menggunakan @ManyToMany
pemetaan JPA
Ini adalah bagaimana Anda bisa memetakan many-to-many
hubungan tabel dengan JPA dan 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);
}
}
- The
tags
asosiasi dalam Post
entitas hanya mendefinisikan PERSIST
dan MERGE
kaskade jenis. Seperti dijelaskan dalam artikel ini , REMOVE
transisi status entitas tidak masuk akal untuk @ManyToMany
asosiasi JPA karena hal itu dapat memicu penghapusan berantai yang pada akhirnya akan menghapus kedua sisi asosiasi.
- Sebagaimana dijelaskan dalam artikel ini , metode tambah / hapus utilitas wajib jika Anda menggunakan asosiasi dua arah sehingga Anda dapat memastikan bahwa kedua sisi asosiasi tersebut sinkron.
- The
Post
entitas menggunakan entitas pengidentifikasi untuk kesetaraan karena tidak memiliki tombol apa saja bisnis yang unik. Seperti yang dijelaskan dalam artikel ini , Anda dapat menggunakan pengidentifikasi entitas untuk kesetaraan selama Anda memastikan bahwa itu tetap konsisten di semua transisi status entitas .
- The
Tag
entitas memiliki kunci bisnis yang unik yang ditandai dengan Hibernate spesifik @NaturalId
penjelasan. Ketika itu masalahnya, kunci bisnis yang unik adalah kandidat terbaik untuk pemeriksaan kesetaraan .
- The
mappedBy
atribut dari posts
asosiasi dalam Tag
tanda entitas yang, dalam hubungan dua arah ini, Post
entitas memiliki asosiasi. Ini diperlukan karena hanya satu sisi yang dapat memiliki hubungan, dan perubahan hanya disebarkan ke database dari sisi tertentu ini.
- Ini
Set
lebih disukai, karena menggunakan List
dengan @ManyToMany
kurang efisien.
Untuk detail lebih lanjut tentang cara terbaik untuk memetakan @ManyToMany
hubungan dengan JPA dan Hibernate, lihat artikel ini .