Relasi One to Many Hibernate Anotasi
Bismillah,
Artikel kali ini adalah lanjutan dari sebelumnya yang masih membahas mengenai relasi/asosiasi pada framework hibernate, yaitu one to many atau disimbolkan anotasi @OneToMany
. Asosiasi ini dimana sebuah entitas dapat menerima atau meng-set informasi dari banyak instance dari entitas, sebagai contoh misalkan relasi yang terjadi antara entitas Mahasiswa
dengan entitas Mata Kuliah
. Misalkan ada si fulan yang mengambil matakuliah algoritma dan pemrograman, praktikum algoritma dan pemrograman, struktur data, praktikum struktur data, dan agama. Sama halnya dengan asosiasi yang sebelumnya telah kita pelajari, @OneToMany
juga memiliki model Unidirectional
dan BidiRectional
. Beberapa penerapan @OneToMany
yang dapat diterapkan menggunakan hibernate adalah sebagai berikut
<a href="#@OneToMany-Unidirectional">@OneToMany</a>
Unidirectional<a href="#@OneToMany-Unidirectional-Join-Kolom">@OneToMany</a>
Unidirectional Join Kolom<a href="#@OneToMany-Unidirectional-Join-Tabel">@OneToMany</a>
Unidirectional Join Tabel<a href="#@OneToMany-Bidirectional">@OneToMany</a>
Bidirectional
@OneToMany
Unidirectional {#@OneToMany-Unidirectional}
@OneToMany
Unidirectional yang paling sederhana, ditampilkan seperti pada relasi tabel pada gambar di bawah ini
Jika kita mapping ke dalam class Java yang perlu dilakukan adalah menuliskan kode seperti ini
@Entity
@Table(name = "mahasiswa")
public class Mahasiswa implements Serializable {
@Id
private String nim;
private String nama;
private float ipk;
private String jurusan;
@OneToMany(cascade = CascadeType.ALL, fetch = FetchType.LAZY, orphanRemoval = true)
private List<MataKuliah> mataKuliahs = new ArrayList<MataKuliah>();
public Mahasiswa() {
}
public Mahasiswa(String nim, String nama, float ipk, String jurusan) {
this.nim = nim;
this.nama = nama;
this.ipk = ipk;
this.jurusan = jurusan;
}
//getter setter silakan digenerate menggunakan IDE
Dari potongan kode di atas setelah @OneToMany
dengan property yang sebelumnya telah kita gunakan sehingga tidak perlu diperjelas kembali, ada instance mataKuliahs
bertipe collection. Tujuan dari instance tersebut adalah agar instance Mahasiswa
dapat menerima dan meng-set data dari entitas Alamat
. Jika menggunaan model seperti ini, hibernate akan membuat tabel baru yang menyimpan informasi primary key kedua entitas. Jika pada contoh di atas tabel tersebut adalah "mahasiswa_mata_kuliah"
, jika kita lihat sql yang dijalankan oleh hibernate adalah sebagai berikut
Hibernate: insert into mahasiswa (ipk, jurusan, nama, nim) values (?, ?, ?, ?) Hibernate: insert into mata_kuliah (namaMataKuliah, sks, kodeMataKuliah) values (?, ?, ?) Hibernate: insert into mata_kuliah (namaMataKuliah, sks, kodeMataKuliah) values (?, ?, ?) Hibernate: insert into mata_kuliah (namaMataKuliah, sks, kodeMataKuliah) values (?, ?, ?) Hibernate: insert into mata_kuliah (namaMataKuliah, sks, kodeMataKuliah) values (?, ?, ?) Hibernate: insert into mahasiswa_mata_kuliah (Mahasiswa_nim, mataKuliahs_kodeMataKuliah) values (?, ?) Hibernate: insert into mahasiswa_mata_kuliah (Mahasiswa_nim, mataKuliahs_kodeMataKuliah) values (?, ?) Hibernate: insert into mahasiswa_mata_kuliah (Mahasiswa_nim, mataKuliahs_kodeMataKuliah) values (?, ?) Hibernate: insert into mahasiswa_mata_kuliah (Mahasiswa_nim, mataKuliahs_kodeMataKuliah) values (?, ?)
Wow, banyak sekali query insert yang dieksekusi karena ada 3 tabel yang harus diinsert data. Sepertinya model seperti ini tidak efisien, bayangnya jika datanya ada 10, 100, atau 1000? 🙁
@OneToMany
Unidirectional Join Kolom {#@OneToMany-Unidirectional-Join-Kolom}
Model lain Unidirectional
yang lain adalah Join kolom, anotasi yang digunakan setelah @OneToMany
adalah @JoinColumn
. Ketika menggunakan join kolom berarti akan ada kolom salah satu entitas menjadi foreign key pada entitas yang lain. Relasi tabel pada database relational ditunjukkan pada gambar di bawah ini
Mapping class Java untuk kedua entitas di atas adalah sebagai berikut
@Entity
@Table(name = "mahasiswa")
public class Mahasiswa implements Serializable {
@Id
private String nim;
private String nama;
private float ipk;
private String jurusan;
@OneToMany(cascade = CascadeType.ALL, fetch = FetchType.LAZY, orphanRemoval = true)
@JoinColumn(name = "nim")
private List<MataKuliah> mataKuliahs = new ArrayList<MataKuliah>();
public Mahasiswa() {
}
public Mahasiswa(String nim, String nama, float ipk, String jurusan) {
this.nim = nim;
this.nama = nama;
this.ipk = ipk;
this.jurusan = jurusan;
}
//getter setter silakan generate menggunakan IDE
Mirip dengan deklarasi yang sebelumnya, hanya menambahkan @JoinColumn
setelah @OneToMany
. Ketika menggunakan model relasi jenis ini hanya akan dibuatkan 2 tabel, tetapi kolom nim
akan menjadi foreign key pada entitas MataKuliah
. Kemudian sql yang dijalankan ketika proses insert oleh hibernate adalah sebagai berikut
Hibernate: insert into mahasiswa (ipk, jurusan, nama, nim) values (?, ?, ?, ?) Hibernate: insert into mata_kuliah (nama_mata_kuliah, sks, kode_mata_kuliah) values (?, ?, ?) Hibernate: insert into mata_kuliah (nama_mata_kuliah, sks, kode_mata_kuliah) values (?, ?, ?) Hibernate: insert into mata_kuliah (nama_mata_kuliah, sks, kode_mata_kuliah) values (?, ?, ?) Hibernate: insert into mata_kuliah (nama_mata_kuliah, sks, kode_mata_kuliah) values (?, ?, ?) Hibernate: update mata_kuliah set nim=? where kode_mata_kuliah=? Hibernate: update mata_kuliah set nim=? where kode_mata_kuliah=? Hibernate: update mata_kuliah set nim=? where kode_mata_kuliah=? Hibernate: update mata_kuliah set nim=? where kode_mata_kuliah=?
Ternyata query yang dijalankan masih belum efisen, perbedaaannya terdapat query update ketika hibernate menjalankan method save()
.
@OneToMany
Unidirectional Join Tabel {#@OneToMany-Unidirectional-Join-Tabel}
Sama seperti yang model yang pertama sebenarnya, perbedaannya adalah ketika menggunakan model jenis ini nama tabel dan kolom-kolomnya yang menghubungkan kedua entitas dapat diberi nama sesuai yang kita inginkan. Anotasi yang digunakan setelah @OneToMany
menggunakan @JoinTable
, mapping class Java dapat dicontohkan seperti berikut ini
@Entity
@Table(name = "mahasiswa")
public class Mahasiswa implements Serializable {
@Id
private String nim;
private String nama;
private float ipk;
private String jurusan;
@OneToMany(cascade = CascadeType.ALL, fetch = FetchType.LAZY, orphanRemoval = true)
@JoinTable(name = "mhs_mk", joinColumns = @JoinColumn(name = "nim"), inverseJoinColumns = @JoinColumn(name = "kode_mk"))
private List<MataKuliah> mataKuliahs = new ArrayList<MataKuliah>();
public Mahasiswa() {
}
public Mahasiswa(String nim, String nama, float ipk, String jurusan) {
this.nim = nim;
this.nama = nama;
this.ipk = ipk;
this.jurusan = jurusan;
}
Dari kode di atas terdapat baris @JoinTable(name = "mhs_mk", joinColumns = @JoinColumn(name = "nim"), inverseJoinColumns = @JoinColumn(name = "kode_mk"))
maksudnya adalah akan membuat sebuah tabel dengan nama "mhs_mk"
dengan kolom "nim"
dan kolom "kode_mk"
.
@OneToMany
Bidirectional {#@OneToMany-Bidirectional}
Model jenis ini merupakan relasi yang paling efisien untuk dapat digunakan pada aplikasi yang akan Anda bangun, jika pada ERD seperti di bawah ini
Gambar ERD di atas memang mirip dengan anotasi menggunakan @OneToMany Unidirectional
join kolom, perbedaaanya adalah pada class Java mappingnya. Mapping tersebut dapat dilihat pada potongan kode di bawah ini
@Entity
@Table(name = "mahasiswa")
public class Mahasiswa implements Serializable {
@Id
private String nim;
private String nama;
private float ipk;
private String jurusan;
@OneToMany(mappedBy = "mahasiswa", cascade = CascadeType.ALL, orphanRemoval = true)
private List<MataKuliah> mataKuliahs = new ArrayList<MataKuliah>();
public Mahasiswa() {
}
public Mahasiswa(String nim, String nama, float ipk, String jurusan) {
this.nim = nim;
this.nama = nama;
this.ipk = ipk;
this.jurusan = jurusan;
}
//getter setter silakan digenerate menggunakan IDE
Dengan menambahakan property mappedBy = "mahasiswa"
pada @OneToMany
berfungsi untuk memapping instance mahasiswa ke dalam entitas MataKuliah
, selanjutnya untuk entitas MataKuliah
java class mapping adalah sebagai berikut
@Entity
@Table(name = "mata_kuliah")
public class MataKuliah implements Serializable {
@Id
@Column(name = "kode_mata_kuliah")
private String kodeMataKuliah;
@Column(name = "nama_mata_kuliah")
private String namaMataKuliah;
private short sks;
@ManyToOne(fetch = FetchType.LAZY)
@JoinColumn(name = "nim")
private Mahasiswa mahasiswa;
public MataKuliah() {
}
public MataKuliah(String kodeMataKuliah, String namaMataKuliah, short sks) {
this.kodeMataKuliah = kodeMataKuliah;
this.namaMataKuliah = namaMataKuliah;
this.sks = sks;
}
//Silakan getter dan setter digenerated menggunakan IDE
Berbeda dari yang sebelumnya pada entitas MataKuliah
ditambahkan @ManyToOne(fetch = FetchType.LAZY)
atau kebalikan dari relasi @OneToMany
pada entitas Mahasiswa
, fetch = FetchType.LAZY
bertujuan agar ketika instance Mahasiswa
load data tidak semua data yang terdapat pada entitas MataKuliah
tidak terload. Sementara untuk query yang dijalankan oleh hibernate adalah sebagai berikut
Hibernate: insert into mahasiswa (ipk, jurusan, nama, nim) values (?, ?, ?, ?) Hibernate: insert into mata_kuliah (nim, nama_mata_kuliah, sks, kode_mata_kuliah) values (?, ?, ?, ?) Hibernate: insert into mata_kuliah (nim, nama_mata_kuliah, sks, kode_mata_kuliah) values (?, ?, ?, ?) Hibernate: insert into mata_kuliah (nim, nama_mata_kuliah, sks, kode_mata_kuliah) values (?, ?, ?, ?) Hibernate: insert into mata_kuliah (nim, nama_mata_kuliah, sks, kode_mata_kuliah) values (?, ?, ?, ?)
Terlihat dari output ketika method save()
dijalankan, querynya lebih sederhana dibanding dengan @OneToMany
yang sebelumnya. Untuk kode di atas dapat didapatkan di sini.
Demikian tulisan saya tentang relasi one to many menggunakan hibernate, semoga bermanfaat dan menjadi ilmu yang baru untuk temen-temen yang baru belajar hibernate seperti saya. Saran dan kritik senantiasa dinantikan untuk memperbaiki kekurangan tulisan pada blog ini. ^_^