Hibernate menyediakan property cascade pada hubungan One-To-Many untuk memudahkan kita dalam melakukan operasi basisdata yang berupa data header-detail. Maksudnya header-detail bagaimana? ada satu data sebagai header dan ada beberapa data yang merupakan detail dari data header tersebut. Paling gampang untuk memahaminya menggunakan contoh. Silahkan disimak contoh berikut.
Kita memiliki 2 buah tabel, satu sebagai tabel header yaitu tabel penjualan dan satu lagi tabel penjualan_detail sebagai tabel detail
1 2 3 4 5 |
CREATE TABLE `penjualan` ( `id` int(11) NOT NULL AUTO_INCREMENT, `tanggalTransaksi` date DEFAULT NULL, PRIMARY KEY (`id`) ) ENGINE=InnoDB AUTO_INCREMENT=2 DEFAULT CHARSET=latin1 |
1 2 3 4 5 6 7 8 |
CREATE TABLE `penjualan_detail` ( `id` int(11) NOT NULL AUTO_INCREMENT, `produk` varchar(255) DEFAULT NULL, `ID_PENJUALAN` int(11) DEFAULT NULL, PRIMARY KEY (`id`), KEY `FK_5b57ccb5067e47aabd6d0f856f9` (`ID_PENJUALAN`), CONSTRAINT `FK_5b57ccb5067e47aabd6d0f856f9` FOREIGN KEY (`ID_PENJUALAN`) REFERENCES `penjualan` (`id`) ) ENGINE=InnoDB AUTO_INCREMENT=3 DEFAULT CHARSET=latin1 |
Gambar relasi kedua tabel diatas seperti pada gambar dibawah ini
Jadi 1 header penjualan memiliki banyak detail penjualan rinci.
Kelas Domain
Seperti biasa kalau menggunakan ORM, kita buat kelas domainnya untuk mapping tabel pada basisdata
file : Penjualan.java
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 |
package com.agungsetiawan.hibernatecascade.entity; import java.util.ArrayList; import java.util.Date; import java.util.List; import javax.persistence.Entity; import javax.persistence.GeneratedValue; import javax.persistence.GenerationType; import javax.persistence.Id; import javax.persistence.OneToMany; import javax.persistence.Table; import javax.persistence.Temporal; /** * * @author Agung Setiawan */ @Entity @Table(name = "PENJUALAN") public class Penjualan { @Id @GeneratedValue(strategy = GenerationType.IDENTITY) private Integer id; @Temporal(javax.persistence.TemporalType.DATE) private Date tanggalTransaksi; @OneToMany(mappedBy = "penjualan") List<PenjualanDetail> penjualanDetails=new ArrayList<PenjualanDetail>(); public Integer getId() { return id; } public void setId(Integer id) { this.id = id; } public Date getTanggalTransaksi() { return tanggalTransaksi; } public void setTanggalTransaksi(Date tanggalTransaksi) { this.tanggalTransaksi = tanggalTransaksi; } public List<PenjualanDetail> getPenjualanDetails() { return penjualanDetails; } public void setPenjualanDetails(List<PenjualanDetail> penjualanDetails) { this.penjualanDetails = penjualanDetails; } } |
file : PenjualanDetail.java
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 |
package com.agungsetiawan.hibernatecascade.entity; import javax.persistence.Entity; import javax.persistence.GeneratedValue; import javax.persistence.GenerationType; import javax.persistence.Id; import javax.persistence.JoinColumn; import javax.persistence.ManyToOne; import javax.persistence.Table; /** * * @author Agung Setiawan */ @Entity @Table(name = "PENJUALAN_DETAIL") public class PenjualanDetail { @Id @GeneratedValue(strategy = GenerationType.IDENTITY) private Integer id; @ManyToOne @JoinColumn(name = "ID_PENJUALAN") private Penjualan penjualan; private String produk; public Integer getId() { return id; } public void setId(Integer id) { this.id = id; } public Penjualan getPenjualan() { return penjualan; } public void setPenjualan(Penjualan penjualan) { this.penjualan = penjualan; } public String getProduk() { return produk; } public void setProduk(String produk) { this.produk = produk; } } |
Kelas Utama
Tanpa Cascade
Tanpa menggunakan cascade maka kita harus melakukan save baik pada Penjualan maupun pada PenjualanDetail. Jika ada 10 PenjualanDetail, kita lakukan 10 kali save pada PenjualanDetail.
Perhatikan pada bagian yang saya highlight
file : App.java
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 |
package com.agungsetiawan.hibernatecascade; import com.agungsetiawan.hibernatecascade.entity.Penjualan; import com.agungsetiawan.hibernatecascade.entity.PenjualanDetail; import com.agungsetiawan.hibernatecascade.util.HibernateUtil; import java.util.Date; import org.hibernate.Session; /** * * @author Agung Setiawan */ public class App { public static void main( String[] args ) { Session session= HibernateUtil.getSessionFactory().openSession(); session.beginTransaction(); Penjualan penjualan=new Penjualan(); penjualan.setTanggalTransaksi(new Date()); PenjualanDetail detail=new PenjualanDetail(); PenjualanDetail detail2=new PenjualanDetail(); detail.setProduk("Windows 7 Asli"); detail.setPenjualan(penjualan); detail2.setProduk("Windows 7 Bajakan"); detail2.setPenjualan(penjualan); penjualan.getPenjualanDetails().add(detail); penjualan.getPenjualanDetails().add(detail2); session.save(penjualan); session.save(detail); session.save(detail2); session.getTransaction().commit(); session.close(); } } |
Dan SQL yang dihasilkan adalah sebagai berikut
1 2 3 |
Hibernate: insert into PENJUALAN (tanggalTransaksi) values (?) Hibernate: insert into PENJUALAN_DETAIL (ID_PENJUALAN, produk) values (?, ?) Hibernate: insert into PENJUALAN_DETAIL (ID_PENJUALAN, produk) values (?, ?) |
Menggunakan Cascade
Jika menggunakan cascade maka kita hanya perlu melakukan save pada kelas yang merupakan header, dalam kasus ini adalah kelas Penjualan. Kita ubah kode pada kelas utama menjadi seperti ini.
file : App.java
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 |
package com.agungsetiawan.hibernatecascade; import com.agungsetiawan.hibernatecascade.entity.Penjualan; import com.agungsetiawan.hibernatecascade.entity.PenjualanDetail; import com.agungsetiawan.hibernatecascade.util.HibernateUtil; import java.util.Date; import org.hibernate.Session; /** * * @author Agung Setiawan */ public class App { public static void main( String[] args ) { Session session= HibernateUtil.getSessionFactory().openSession(); session.beginTransaction(); Penjualan penjualan=new Penjualan(); penjualan.setTanggalTransaksi(new Date()); PenjualanDetail detail=new PenjualanDetail(); PenjualanDetail detail2=new PenjualanDetail(); detail.setProduk("Windows 7 Asli"); detail.setPenjualan(penjualan); detail2.setProduk("Windows 7 Bajakan"); detail2.setPenjualan(penjualan); penjualan.getPenjualanDetails().add(detail); penjualan.getPenjualanDetails().add(detail2); session.save(penjualan); session.getTransaction().commit(); session.close(); } } |
Dan ketika dijalankanpun akan menghasilkan SQL yang sama
1 2 3 |
Hibernate: insert into PENJUALAN (tanggalTransaksi) values (?) Hibernate: insert into PENJUALAN_DETAIL (ID_PENJUALAN, produk) values (?, ?) Hibernate: insert into PENJUALAN_DETAIL (ID_PENJUALAN, produk) values (?, ?) |
Mengaktifkan Cascade
Untuk mengaktifkan cascade cukup kita tambahkan property cascade pada annotaion OneToMany di header, yaitu kelas Penjualan.
tanpa cascade
1 2 |
@OneToMany(mappedBy = "penjualan") List<PenjualanDetail> penjualanDetails=new ArrayList<PenjualanDetail>(); |
dengan cascade
1 2 |
@OneToMany(mappedBy = "penjualan",cascade = CascadeType.ALL) List<PenjualanDetail> penjualanDetails=new ArrayList<PenjualanDetail>(); |
Referensi
[1] Guruzu, Srinivas and Gary Mak, Hibernate Recipes A Problem-Solution Approach, Apress, New York City, 2010