noprianto
noprianto
. 8 min read

Relasi Many to Many Hibernate Anotasi

Bismillah,
Many to many adalah jenis relasi yang terakhir untuk menangai bertukarnya informasi antar entitas, jika pada artikel sebelumnya terdapat banyak mekanisme yang dapat digunakan walaupun tidak semua optimal. Sedangkan pada relasi many to many tidak banyak model yang dapat digunakan, hibernate untuk melakukan relasi ini menggunakan anotasi @ManyToMany. Hal yang menjadi perhatian adalah ketika menggunakan relasi ini, pasti akan terbentuk sebuah tabel baru oleh hibernate. Ilustrasi penerapan relasi many to many misalnya ketika relasi yang terjadi antara Mahasiswa dengan sebuah Tugas, bisa saja satu mahasiswa mengerjakan tugas yang banyak dan juga tugas yang sama dikerjakan oleh banyak mahasiswa. Beberapa model @ManyToMany yang digunakan hibernate adalah sebagai berikut

@ManyToMany Unidirectional {#@ManyToMany-Unidirectional}

Sama halnya dengan relasi pendahulu, @ManyToMany juga terdapat model relasi unidirectional. Misalkan kita memiliki relasi ERD seperti gambar di bawah ini

Many to many unidirectional <figcaption>Many to many unidirectional</figcaption></figure>

Setelah kita mapping ke dalam class java berarti membutuhkan class Tugas dan class Mahasiswa, sedangkan class MahasiswaTugas tidak perlu dibuat karena akan digenerate oleh hibernate.

@Entity
@Table(name = "mahasiswa")
public class Mahasiswa implements Serializable {

    @Id
    private String nim;
    private String nama;
    private float ipk;
    private String jurusan;
    @ManyToMany(cascade = CascadeType.ALL)
    private List<Tugas> tugases = new ArrayList<>();

    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 dengan IDE

Dengan menambahkan anotasi @ManyToMany untuk menginformasikan bahwa entitas Mahasiswa berinteraksi dengan entitas Tugas, hampir sama dengan @OneToMany yaitu membuatkan field collection List dengan wrapper class Tugas. Sedangkan entitas Tugas hanya mendefiniskan entitas biasa, tidak ada yang perlu dikonfigurasi seperti entitas Mahasiswa. Ketika dijalankan proses insert menggunakan hibernate, query yang tampil pada output editor Anda adalah sebagai berikut

Hibernate: insert into mahasiswa (ipk, jurusan, nama, nim) values (?, ?, ?, ?)
Hibernate: insert into tugas (nama, tanggal_submitted, id) values (?, ?, ?)
Hibernate: insert into tugas (nama, tanggal_submitted, id) values (?, ?, ?)
Hibernate: insert into mahasiswa_tugas (Mahasiswa_nim, tugases_id) values (?, ?)
Hibernate: insert into mahasiswa_tugas (Mahasiswa_nim, tugases_id) values (?, ?)
Hibernate: select mahasiswa_.nim, mahasiswa_.ipk as ipk2_0_, mahasiswa_.jurusan as jurusan3_0_, mahasiswa_.nama as nama4_0_ from mahasiswa mahasiswa_ where mahasiswa_.nim=?
Hibernate: insert into mahasiswa (ipk, jurusan, nama, nim) values (?, ?, ?, ?)
Hibernate: insert into mahasiswa_tugas (Mahasiswa_nim, tugases_id) values (?, ?)

Jika dilihat query di atas, terdapat query insert ke tabel penghubung yaitu mahasiswa_tugas. Sebenarnya selain cara di atas, ada lagi yaitu menggunakan anotasi @JoinTable sehingga kita dapat mendefiniskan nama tabel penghubung dan kolomnya dapat didefiniskan sesuai dengan keinginan kita.

@ManyToMany Bidirectional {#@ManyToMany-Bidirectional}

Dengan Bidirectional sebenarnya masih sama dari sisi stuktur tabel di database seperti di atas, tetapi berbeda dari sisi mapping class java karena kedua entitas harus bisa saling bertukar informasi. Untuk entitas Mahasiswa masih sama, yang berbeda adalah pada entitas Tugas seperti berikut

@Entity
@Table(name = "tugas")
public class Tugas implements Serializable {

    @Id
    @GeneratedValue
    private int id;
    private String nama;
    @Temporal(javax.persistence.TemporalType.DATE)
    private Date tanggal_submitted;
    @ManyToMany(mappedBy = "tugases")
    private List<Mahasiswa> mahasiswas = new ArrayList<>();

    public Tugas() {
    }

    public Tugas(String nama, Date tanggal_submitted) {
        this.nama = nama;
        this.tanggal_submitted = tanggal_submitted;
    }

//Getter dan setter silakan digenerate menggunakan IDE

Karena Bidirectional sehingga membutuhkan anotasi @ManyToMany juga pada entitas Tugas, mappedBy = "tugases" berarti pada entitas Mahasiswa akan ada instance dengan nama tugases.

Selain model-model di atas, yang dapat dilakukan teknik lain adalah @ManyToMany dengan melakukan linked pada sebuah entitas. Teknik ini menurut saya dari sisi codingan lebih banyak karena harus mengimplementasi template CRUD dari hibernate pada kedua entitasnya, relasi yang terjadi pada tabel di database ditunjukkan pada gambar di bawah ini

Many to many bidirectional
Many to many bidirectional

Kemudian untuk mapping class java dari gambar di atas, dapat dicontohkan seperti 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<MahasiswaTugas> tugases = new ArrayList<>();

    public Mahasiswa() {
    }

    public Mahasiswa(String nim, String nama, float ipk, String jurusan) {
        this.nim = nim;
        this.nama = nama;
        this.ipk = ipk;
        this.jurusan = jurusan;
    }

    public String getNim() {
        return nim;
    }

    public void setNim(String nim) {
        this.nim = nim;
    }

    public String getNama() {
        return nama;
    }

    public void setNama(String nama) {
        this.nama = nama;
    }

    public float getIpk() {
        return ipk;
    }

    public void setIpk(float ipk) {
        this.ipk = ipk;
    }

    public String getJurusan() {
        return jurusan;
    }

    public void setJurusan(String jurusan) {
        this.jurusan = jurusan;
    }

    public void addTugas(Tugas tugas) {
        MahasiswaTugas mahasiswaTugas = new MahasiswaTugas(this, tugas);
        tugases.add(mahasiswaTugas);
        tugas.getMahasiswas().add(mahasiswaTugas);
    }

    public void removeTugas(Tugas tugas) {
        MahasiswaTugas mahasiswaTugas = new MahasiswaTugas(this, tugas);
        tugas.getMahasiswas().remove(mahasiswaTugas);
        tugases.remove(mahasiswaTugas);
        mahasiswaTugas.setMahasiswa(null);
        mahasiswaTugas.setTugas(null);
    }

    public List<MahasiswaTugas> getTugases() {
        return tugases;
    }

    public void setTugases(List<MahasiswaTugas> tugases) {
        this.tugases = tugases;
    }

    @Override
    public String toString() {
        return "Mahasiswa{" + "nim=" + nim + ", nama=" + nama + ", ipk=" + ipk + ", jurusan=" + jurusan + '}';
    }

    @Override
    public int hashCode() {
        int hash = 7;
        hash = 59 * hash + Objects.hashCode(this.nim);
        hash = 59 * hash + Objects.hashCode(this.nama);
        hash = 59 * hash + Float.floatToIntBits(this.ipk);
        hash = 59 * hash + Objects.hashCode(this.jurusan);
        return hash;
    }

    @Override
    public boolean equals(Object obj) {
        if (this == obj) {
            return true;
        }
        if (obj == null) {
            return false;
        }
        if (getClass() != obj.getClass()) {
            return false;
        }
        final Mahasiswa other = (Mahasiswa) obj;
        if (Float.floatToIntBits(this.ipk) != Float.floatToIntBits(other.ipk)) {
            return false;
        }
        if (!Objects.equals(this.nim, other.nim)) {
            return false;
        }
        if (!Objects.equals(this.nama, other.nama)) {
            return false;
        }
        if (!Objects.equals(this.jurusan, other.jurusan)) {
            return false;
        }
        return true;
    }

}

Yang berbeda dari yang sebelumnya adalah bahwa terdapat method addTugas() dan removeTugas() untuk menghapus dari instance Tugas. Kemudian untuk entitas Tugas potongan kodenya adalah sebagai berikut

@Entity
@Table(name = "tugas")
public class Tugas implements Serializable {

    @Id
    @GeneratedValue
    private int id;
    private String nama;
    @Temporal(javax.persistence.TemporalType.DATE)
    private Date tanggal_submitted;
    @OneToMany(mappedBy = "tugas",cascade = CascadeType.ALL,orphanRemoval = true)
    private List<MahasiswaTugas> mahasiswas = new ArrayList<>();

    public Tugas() {
    }

    public Tugas(String nama, Date tanggal_submitted) {
        this.nama = nama;
        this.tanggal_submitted = tanggal_submitted;
    }

//Getter dan setter silakan generate menggunakan IDE

Karena Bidirectional sehingga pada kedua entitas memiliki anotasi @OneToMany, dari anotasi tersebut nanti dibutuhkan mapping entitas untuk menjembatani kedua entitas tersebut yaitu entitas MahasiswaTugas. Potongan kode yang dapat digunakan adalah sebagai berikut

@Entity
@Table(name = "mhs_tgs")
public class MahasiswaTugas implements Serializable {

    @Id
    @ManyToOne
    private Mahasiswa mahasiswa;
    @Id
    @ManyToOne
    private Tugas tugas;

    public MahasiswaTugas() {
    }

    public MahasiswaTugas(Mahasiswa mahasiswa, Tugas tugas) {
        this.mahasiswa = mahasiswa;
        this.tugas = tugas;
    }

Entitas di atas dilakukan linking ke dua entitas yaitu dengan menambahkan @Id dan anotasi @ManyToOne, berfungsi untuk merelasikan kedua identifier yang terdapat pada entitas Mahasiswa dan entitas Tugas. Untuk code lengkap di atas dapat didapatkan di sini.

Penutup

Demikianlah artikel saya mengenai anotasi @ManyTo@Many, semoga bermanfaat dan dapat diterapkan dalam kasus yang ditemukan dalam dunia nyata untuk aplikasi yang akan dibangun. Kritik dan saran senantiasa diharapkan untuk memperbaiki artikel-artikel yang ditulis. 🙂

Referensi

comments powered by Disqus