One-to-One Bi-Directional
Pada materi sebelumnya kita sudah membahas tentang Bi-Directional dan Uni-Directional. Sekarang kita akan mengimplementasikan dalam relasi One-to-One, dimana dalam kasus ini Classes mengetahui siapa gurunya, tetapi Teacher tidak tahu ia mengajar kelas mana (di dalam kode Java). Dengan Bi-directional (dua arah) nantinya kedua entity saling mengetahui keberadaan satu sama lain.
1️⃣ Konsep Utama: The mappedBy Attribute
Dalam relasi dua arah, harus ada satu sisi yang menjadi Pemilik (Owner) dan satu sisi yang menjadi Pendukung (Non-Owner).
- Owner (Classes): Sisi yang memiliki kolom Foreign Key (
teacher_id) di tabel database. - Non-Owner (Teacher): Sisi yang menggunakan atribut
mappedBy. Atribut ini memberitahu Hibernate: "Jangan buat kolom baru di tabelku, lihat saja pemetaan yang sudah ada di kelasClasses."
2️⃣ Implementasi Entity
A. Sisi Pemilik (Owner) - Classes
Di sini kita meletakkan @JoinColumn.
@Entity
@Table(name = "classes")
public class Classes {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;
@Column(name = "class_name")
private String className;
@OneToOne(cascade = CascadeType.ALL)
@JoinColumn(name = "teacher_id", referencedColumnName = "id")
private Teacher teacher; // Navigasi: Classes -> Teacher
// Setter & Getter
}
B. Sisi Pendukung (Non-Owner) - Teacher
Di sini kita menggunakan mappedBy yang merujuk pada nama variabel di kelas Classes.
@Entity
@Table(name = "teacher")
public class Teacher {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;
@Column(name = "first_name")
private String firstName;
@Column(name = "last_name")
private String lastName;
@OneToOne(mappedBy = "teacher", // Merujuk ke field 'teacher' di class Classes
cascade = CascadeType.ALL) // setiap operasi yang dilakukan pada entity ini akan otomatis diteruskan ke entity yang terhubung (Child).
private Classes classes; // Navigasi: Teacher -> Classes
// Setter & Getter
}
🤑 Keuntungan Bi-Directional
- Navigasi Mudah: Anda bisa mendapatkan data
Classeshanya dengan objekTeacher.
Teacher tempTeacher = dao.findTeacherById(1);
System.out.println("Guru ini wali kelas dari: " + tempTeacher.getClasses().getClassName());
- Fleksibilitas Query: Memudahkan penulisan JPQL karena Anda bisa melakukan join dari kedua sisi.
3️⃣ Implementasi DAO
Dalam hubungan dua arah, kita bisa melakukan pencarian data dari sisi mana pun. Kita dapat menambahkan metode untuk mencari dan menghapus baik dari sisi Classes maupun Teacher.
Pada materi Uni-Directional One-to-One sebelumnya kita hanya dapat menampilkan data hanya dari sisi Classes, kali ini kita akan menampilkan data dari sisi Teacher:
- Tambahkan kontrak metode
findTeacherById(Integer id)pada interface DAO:
public interface SchoolDAO {
void saveClasses(Classes classes);
Classes findClassById(Integer id);
void deleteClassesById(Integer id);
Teacher findTeacherById(Integer id);
}
- Implementasi pada
SchoolDAOImpl:
@Repository
public class SchoolDAOImpl implements SchoolDAO {
private EntityManager entityManager;
public SchoolDAOImpl(EntityManager entityManager) {
this.entityManager = entityManager;
}
@Override
@Transactional
public void saveClasses(Classes classes) {
entityManager.persist(classes);
}
@Override
@Transactional(readOnly = true)
public Classes findClassById(Integer id) {
return entityManager.find(Classes.class, id);
}
@Override
@Transactional
public void deleteClassesById(Integer id) {
entityManager.remove(entityManager.find(Classes.class, id));
}
@Override
@Transactional(readOnly = true)
public Teacher findTeacherById(Integer id) {
return entityManager.find(Teacher.class, id);
}
}
🔥 Main Application
- Dengan implementasi Bi-Directional ini, Anda bisa melakukan navigasi "bolak-balik" seperti contoh di bawah ini:
@SpringBootApplication
public class Application {
public static void main(String[] args) {
SpringApplication.run(Application.class, args);
}
// Bean ini akan dieksekusi di command line
@Bean
public CommandLineRunner commandLineRunner(SchoolDAO dao) {
return runner -> {
findTeacher(dao);
};
}
private void findTeacher(SchoolDAO dao) {
Integer id = 1;
Teacher teacher = dao.findTeacherById(id);
System.out.println("Teacher found = " + teacher);
System.out.println("Teacher Class detail = " + teacher.getClasses());
}
}
- Output pada console hibernate:
Hibernate: select t1_0.id,c1_0.id,c1_0.class_name,t1_0.first_name,t1_0.last_name from teacher t1_0 left join classes c1_0 on t1_0.id=c1_0.teacher_id where t1_0.id=?
Teacher found = Guru [id=1, firstName=Andi, lastName=Fahrum]
Teacher Class detail = Class [id=1, className=Kelas 9, teacher=Guru [id=1, firstName=Andi, lastName=Fahrum]]