noprianto
noprianto
. 9 min read

Relasi One to One Hibernate Anotasi

Bismillah,
Jika pada artikel sebelumnya kita telah membahas mengenai identifier di hibernate, pada kesempatan ini akan belajar mengenai relasi atau sering disebut assosiasi. Aplikasi yang akan kita bangun mustahil jika entitas tidak berelasi dengan entitas yang lain, walaupun aplikasi yang sederhana pun. Bisa saja aplikasi yang kita bangun hanya terdapat 1 entitas atau tidak ada relasi antar entitas, tapi fungsi aplikasi tidak akan maksimal.

Tujuan dari relasi antar entitas adalah agar bisa saling bertukar informasi, ada dua model relasi yang sering kita dengar yaitu Unidirectional dan Bidirectional. Unidirectional adalah hanya akan ada salah satu entitas yang bertukar informasi, sebaliknya Bidirectional berarti antar entitas bisa saling bertukar informasi. Relasi yang dapat digunakan adalah OneToOne, OneToMany, dan ManyToMany. Tetapi pada kesempatan ini yang akan kita bahas adalah relasi OneToOne, pokok bahasan yang dapat disajikan adalah sebagai berikut

@OneToOne Join Kolom Unidirectional {#@OneToOne-Join-Kolom-Unidirectional}

Salah satu model yang digunakan adalah join kolom, pada hibernate menggunakan anotasi @JoinColumn setelah anotasi @OneToOne. Misalkan kita punya relasi di database seperti gambar di bawah ini

One to one relational
One to one relational join kolom

Dari gambar di atas akan kita coba mapping ke dalam class Java seperti di bawah ini menggunakan anotasi @OneToOne dengan model @JoinColumn.

@Entity
@Table
public class Mahasiswa implements Serializable {

    @Id
    private String nim;
    private String nama;
    private float ipk;
    private String jurusan;
    @OneToOne(cascade = CascadeType.ALL, fetch = FetchType.LAZY, orphanRemoval = true)
    @JoinColumn(name = "alamat_id")
    private Alamat alamat;

    public Mahasiswa() {
    }

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

//Getter setter bisa digenerate menggunakan IDE

Sementara untuk entitas Alamat standard tidak ada yang istimewa, beberapa property yang sebelumnya belum digunakan cascade = CascadeType.ALL, fetch = FetchType.LAZY, dan orphanRemoval = true. cascade digunakan dalam masalah konsistensi data, CascadeType.ALL berarti semua operasi(update,delete,dll) data berpengaruh ke entitas tersebut. fetch berkaitan dengan retrieve data atau load data ketika ada entitas yang saling berelasi, FetchType.LAZY berarti tidak secara automatis diload atau hanya diload ketika ada objek yang dipanggil. Sedangkan kebalikannya adalah FetchType.EAGER, sementara orphanRemoval = true berfungsi agar ketika menghapus record pada entitas maka akan terhapus juga pada entitas yang berelasi.

Contoh di atas adalah model relasi Unidirectional, dimana class Alamat menjadi instance di dalam class Mahasiswa. Dapat dikatakan bahwa class Mahasiswa dapat mengambil informasi instance dari class Alamat, sedangkan class Alamat tidak bisa melihat informasi class Mahasiswa.

@OneToOne Join Kolom Bidirectional {#@OneToOne-Join-Kolom-Bidirectional}

Jika pada contoh sebelumnya adalah model relasi Unidirectional, kita akan coba untuk contoh yang Bidirectional. Relasi tabel pada database kira-kira seperti ini

One to one relational bidirectional
One to one relational bidirectional

Relasi tabel di atas one to one bidirectional karena satu mahasiswa hanya memiliki satu alamat, alamat bergantung dengan mahasiswa artinya tidak mungkin ada alamat tanpa ada mahasiswa. Setelah kita mapping ke dalam class Java menggunakan hibernate, yang perlu dilakukan adalah sebagai berikut

@Entity
@Table
public class Mahasiswa implements Serializable {

    @Id
    private String nim;
    private String nama;
    private float ipk;
    private String jurusan;
    @OneToOne(mappedBy = "mahasiswa", cascade = CascadeType.ALL, fetch = FetchType.LAZY, orphanRemoval = true)
    private Alamat alamat;

    public Mahasiswa() {
    }

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

    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 Alamat getAlamat() {
        return alamat;
    }

    public void setAlamat(Alamat alamat) {
        if (alamat == null) {
            if (this.alamat != null) {
                this.alamat.setMahasiswa(null);
            }
        } else {
            alamat.setMahasiswa(this);
        }
        this.alamat = alamat;
    }

    public void removeAlamat() {
        if (alamat != null) {
            alamat.setMahasiswa(null);
            alamat = null;
        }
    }

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

}

Pada anotasi @OneToOne terdapat property mappedBy = "mahasiswa", bearti nanti akan ada instance dengan nama “mahasiswa” pada entitas yang lain yaitu entitas Alamat. Selain itu yang method setAlamat() terdapat implementasi yang berbeda, intinya adalah selain set instance alamat dengan parameter yang dilewatkan juga set mahasiswa pada entitas Alamat. Sementara mapping entitas Alamat seperti di bawah ini

@Entity
@Table
public class Alamat implements Serializable {

    @Id
    @GeneratedValue
    private long id;
    private String nama_jalan;
    private int RT;
    private int RW;
    private String kota;
    private String provinsi;
    @OneToOne(fetch = FetchType.LAZY)
    @JoinColumn(name = "nim")
    private Mahasiswa mahasiswa;

    public Alamat() {
    }

    public Alamat(String nama_jalan, int RT, int RW, String kota, String provinsi) {
        this.nama_jalan = nama_jalan;
        this.RT = RT;
        this.RW = RW;
        this.kota = kota;
        this.provinsi = provinsi;
    }

//getter setter silakan digenerate dengan IDE

Pada entitas Alamat terdapat anotasi @OneToOne juga karena Bidirectional yang menandakan bahwa saling bisa berbagi informasi antara kedua entitas. Untuk merelasikan menggunakan anotasi @JoinColumn, berarti nanti ada identifer entitas Mahasiwa yang menjadi foreign key pada entitas Alamat dalam hal ini yaitu "nim". Kemudian untuk unit test juga sedikit berbeda dari yang Unidirectional, bisa dilhat seperti contoh di bawah ini

@Test
    public void testSave() {
        Alamat a = new Alamat("Jln. Simpang Setaman 1", 6, 15, "Malanga", "Jawa Timur");
        Mahasiswa m = new Mahasiswa("075410099", "Noprianto", 3.99F, "Teknologi Informasi", a);
        m.setAlamat(a);
        assertTrue(service.save(m));
    }

Pada unit test terdapat 1 baris perintah m.setAlamat(a) untuk set entitas Mahasiswa, jika hal tersebut tidak dilakukan kolom nim yang terdapat pada tabel alamat nanti nilainya null.

@OneToOne Join Table {#@OneToOne-Join-Table}

Sesuai dengan namanya relasi @OneToOne ini berarti akan membuat sebuah tabel bantu untuk menampung primary key masing-masing entitas. Ilustrasi join tabel digambarkan seperti di bawah ini

One to one join table
One to one join table

Kemudian kita coba mapping ke dalam class Java menggunakan hibernate anotasi yang merepresentasikan tabel relational seperti di atas.

@Entity
@Table
public class Mahasiswa implements Serializable {

    @Id
    private String nim;
    private String nama;
    private float ipk;
    private String jurusan;
    @OneToOne(cascade = CascadeType.ALL, fetch = FetchType.LAZY, orphanRemoval = true)
    @JoinTable(name = "Mahasiswa_Alamat",joinColumns = @JoinColumn(name = "nim"),inverseJoinColumns = @JoinColumn(name = "alamat_id"))
    private Alamat alamat;

    public Mahasiswa() {
    }

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

//getter setter silakan digenerate menggunakan IDE

Untuk melakukan join tabel relasi one to one menggunakan anotasi @JoinTable dengan property seperti name = "Mahasiswa_Alamat",joinColumns = @JoinColumn(name = "nim"),inverseJoinColumns = @JoinColumn(name = "alamat_id") maksudnya adalah membuat tabel baru dengan nama "Mahasiswa_Alamat" dengan "nim" yang dijoinkan dengan "alamat_id".

@OneToOne Share Primary Key {#@OneToOne-Share-Primary-Key}

Mekanisme model relasi ini adalah dengan menjadikan primary key suatu entitas dijadikan primary key juga untuk entitas yang lain, untuk dapat melakukannya tentunya nama kolom dan tipenya harus sama. Hibernate menggunakan anotasi @PrimaryKeyJoinColumn setelah anotasi @OneToOne. Untuk kasus entitas Mahasiswa dan entitas Alamat tidak dapat digunakan sebagai contoh karena identifier pada entitas Mahasiswa bertipe String, sedangkan entitas Alamat bertipe long. Untuk source code bisa didapatkan di github saya.

Demikianlah artikel saya tentang penerapan asosiasi @OneToOne menggunakan hibernate, masih terdapat asosiasi yang lain seperti @OneToMany dan @ManyToMany. Insya alloh pada tulisan yang akan datang akan saya bahas, semoga artikel ini bermanfaat dan menambah pengetahuan baru. Kritik dan saran sangat diharapkan untuk meningkatkan kwalitas blog ini. 🙂

comments powered by Disqus