Pernahkah Anda merasa kebingungan ketika harus mengelola relasi kompleks antar entitas dalam aplikasi Anda? Terutama saat menghadapi situasi di mana satu entitas dapat berhubungan dengan banyak entitas lainnya dan sebaliknya, seperti pada relasi antara Siswa dan Mapel, yang dihubungkan dengan Mapel_Siswa dan memiliki kolom pivot tambahan. Kebingungan ini dapat menghambat alur kerja dan menyebabkan kode menjadi tidak efisien serta sulit dipelihara. Tapi jangan khawatir, dalam artikel ini, kami akan membahas secara rinci tentang bagaimana mengimplementasikan relasi many-to-many menggunakan Spring Boot dan Hibernate, termasuk penggunaan tabel pivot yang memiliki kolom tambahan untuk mengelola relasi tersebut. Dengan panduan ini, Anda akan mampu menangani relasi antar entitas dengan lebih mudah dan efektif, memastikan aplikasi Anda berjalan lebih lancar dan kode lebih mudah untuk dikelola.
ERD
kita bisa gambarkan dulu ERD antara Siswa (SISWA) dan Mata Pelajaran (MAPEL). Digunakan tabel pivot MAPEL_SISWA untuk menghubungkan dua entitas ini, seperti pada gambar di bawah. Bisa dilihat terdapat kolom nilai yang merepresentasikan nilai yang didapat per siswa, per mata pelajaran.
Model
Siswa.java
@Entity
@Data
public class Siswa {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
@Column(name = "NOMOR_INDUK")
private Long nomorInduk;
@Column(name = "NAMA", length = 100)
private String nama;
@OneToMany(mappedBy = "siswa", cascade = CascadeType.ALL, orphanRemoval = true)
private Set<MapelSiswa> mapelSiswaSet = new HashSet<MapelSiswa>();
public Siswa(String nama) {
this.nama = nama;
}
}
Mapel.java
@Entity
@Data
public class Mapel {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
@Column(name = "KODE_MAPEL")
private Long kodeMapel;
@Column(name = "NAMA", length = 100)
private String nama;
@OneToMany(mappedBy = "mapel", cascade = CascadeType.ALL, orphanRemoval = true)
private Set<MapelSiswa> mapelSiswaSet = new HashSet<MapelSiswa>();
}
MapelSiswa.java
@Entity
@Data
public class MapelSiswa {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;
@ManyToOne
@JoinColumn(name = "NOMOR_INDUK")
private Siswa siswa;
@ManyToOne
@JoinColumn(name = "KODE_MAPEL")
private Mapel mapel;
private Integer nilai;
}
Cara yang digunakan dalam pembuatan modelnya adalah oneToMany ke tabel pivot (MapelSiswa), kemudian di tabel pivot ManyToOne ke masing-masing tabel (Mapel & Siswa). Cara seperti ini bisa mempermudah jika semisal kita ingin menambahkan kolom baru, semisal NILAI_UAS, NILAI_UTS, NILAI_ULANGAN_HARIAN, NILAI_REMEDIAL, dsbnya.
Repository
SiswaRepository
@Repository
public interface SiswaRepository extends JpaRepository<Siswa, Long> {
}
MapelRepository
@Repository
public interface MapelRepository extends JpaRepository<Mapel, Long> {
}
MapelSiswaRepository
@Repository
public interface MapelSiswaRepository extends JpaRepository<MapelSiswa, Long>{
}
Tidak ada tambahan fungsi untuk tiap-tiap repository, kita manfaatkan yang sudah ada saja terlebih dahulu. Masing-masing model dibuatkan repositorynya, sehingga terbentuk 3 buah repository yang digunakan untuk mengakses tabel di database.
Service
SekolahService
@Service
@Data
public class SekolahService {
private final MapelSiswaRepository mapelSiswaRepository;
private final SiswaRepository siswaRepository;
private final MapelRepository mapelRepository;
@Transactional(propagation = Propagation.REQUIRED)
public MapelSiswa store(MapelSiswa mapelSiswa) {
if(mapelSiswa.getMapel() != null) {
mapelRepository.save(mapelSiswa.getMapel());
}
if(mapelSiswa.getSiswa() != null) {
siswaRepository.save(mapelSiswa.getSiswa());
}
MapelSiswa save = mapelSiswaRepository.save(mapelSiswa);
return save;
}
@Transactional(propagation = Propagation.REQUIRED)
public void addSiswa(Mapel mapel, Siswa siswa, Integer nilai) {
siswaRepository.save(siswa);
MapelSiswa newKelas = new MapelSiswa();
newKelas.setMapel(mapel);
newKelas.setSiswa(siswa);
newKelas.setNilai(nilai);
mapelSiswaRepository.save(newKelas);
mapel.getMapelSiswaSet().add(newKelas);
}
}
SekolahService dibuat untuk mengakomodir fungsi-fungsi pada modul sekolah. Kita anggap bahwa Mapel, Siswa, termasuk MapelSiswa adalah bagian dari modul sekolah. Terdapat 2 fungsi yaitu store dan addSiswa. Jika diperhatikan pada fungsi store dilakukan save sebanyak 3 kali :
- save ke Mapel lewat baris code mapelRepository.save
- save ke Siswa lewat baris code siswaRepository.save
- dan ke MapelSiswa lewat baris code mapelSiswaRepository.save
Code Test
public static void runSekolah(SekolahService sekolahService) {
Mapel mapel = new Mapel();
mapel.setNama("Biologi");
Siswa siswa = new Siswa("Rudi");
MapelSiswa kelas = new MapelSiswa();
kelas.setMapel(mapel);
kelas.setSiswa(siswa);
kelas.setNilai(90);
sekolahService.store(kelas);
Siswa siswaBaru = new Siswa("John");
sekolahService.addSiswa(mapel, siswaBaru, 65);
}
Untuk melakukan test digunakan fungsi di atas. Secara umum fungsinya terdiri dari 2 yaitu pertama melakukan save ke MapelSiswa baru, dimulai dari Mapel mapel = new Mapel(); sampai sekolahService.store(kelas);. Kemudian yang kedua adalah menambah siswa baru yang bernama John.
Hasil Code
Untuk akses full code bisa dilihat pada github berikut.
Sekian dari saya, mohon maaf atas kekurangan dan terimakasih sudah membaca. Semoga membantu, jangan lupa untuk berkomentar.
Referensi
- https://www.baeldung.com/jpa-many-to-many diakses 12 Juni 2024
- https://www.geeksforgeeks.org/jpa-many-to-many-mapping/ diakses 12 Juni 2024
Posting Komentar untuk "Spring boot Hibernate Basic 7 Memahami Pivot Pada Relasi Many-to-Many"
Berilah komentar, saran, dan kritik dengan bijak