Bi-Directional
κΈ°μ‘΄ Uni-Directional μμλ Instructor λ₯Ό load ν΄μΌλ§ κ·Έμ λν InstructorDetail μ κ°μ Έμ¬ μ
μμλ€.

κ·Έλ¬λ Bi-Directional relationship μ μ¬μ©νλ©΄ InstructorDetail μ load ν¨μΌλ‘μ¨ μ΄μ associated λ Instructor λ₯Ό get ν μ μλ€.
Uni-Directional μμ Bi-Directional λ‘ λ°κΎΈλ κ²μ λ¨μν Java code λ§ μμ νλ©΄ λλ€. κΈ°μ‘΄μ DB schema λ₯Ό μμ ν νμλ μλ€.
Bi-Directional One-to-One Mapping μ Development Process λ λ€μκ³Ό κ°λ€.
- Make updates to
InstructorDetailclass- Add new feild to reference
Instructorwith@OneToOneannotation- Add getter/setter methods for
Instructor- Create Main App
1.1. Add new feild to reference Instructor with @OneToOne annotation
@OneToOne(mappedBy = "instructorDetail", cascade = CascadeType.ALL)
private Instructor instructor;@OneToOne annotation μ ν΅νμ¬ μμ κ°μ΄ field λ₯Ό μ€μ νλ©΄ λλ€. λν mapping λ λ€λ₯Έ entity class μ μ΄λ€ field μ μ°κ΄μ΄ λμ΄μλμ§λ₯Ό mappedBy λ₯Ό ν΅νμ¬ μ€μ ν μ μλ€. μ¬κΈ°μλ Instructor class μ instructorDetail field μ μ°κ΄λ κ²μ΄λ€.
1.2. Add getter/setter methods for Instructor
μ΄νμ instructor μ getter μ setter λ₯Ό μΆκ°νλ€. μ΄λ, toString() method μλ μΆκ°λ instructor field μ λν λ΄μ©μ μΆκ°νλ©΄ μ λλ€.
λ§μ½ λλ²κΉ
μ΄λ κΈ°ν μΆλ ₯μ μνμ¬ entity class object μ체λ₯Ό μΆλ ₯νλ μν©μμ, owning side(FK λ₯Ό 보μ ν μΈ‘, μ£ΌμΈ) μ inverse side(λΉμ£ΌμΈ) λͺ¨λ μλ‘μ object κ° λͺ¨λ κ°κ°μ toString() method μ ν¬ν¨λμ΄ μλ€λ©΄ Infinite Recursion(무ν μ¬κ· νΈμΆ) λλ Circular Reference(μν μ°Έμ‘°) λ¬Έμ κ° λ°μνκ² λλ€.
λ°λΌμ μ€μ FK λ₯Ό 보μ ν owning side μμλ§ toString() μ μΆκ°νλ κ²μ΄ λ°λμ§ν λ°©λ²μΈ κ² κ°λ€.
2. Create Main App
private void findInstructorDetail(AppDAO appDAO) {
int theId = 2;
InstructorDetail tempInstructorDetail = appDAO.findInstructorDetailById(theId);
System.out.println("tempInstructorDetail: " + tempInstructorDetail);
System.out.println("the associated instructor: " + tempInstructorDetail.getInstructor());
System.out.println("Done! :)");
}μ΄λ²μλ Bi-Directional One-To-One mapping μ test νκΈ° μνμ¬ μμ κ°μ΄ InstructorDetail μ ν΅νμ¬ Instructor data λ₯Ό μ½μ΄μ€λλ‘ code λ₯Ό μμ±νλ€.

κ²°κ³Όμ μΌλ‘ μμ κ°μ΄ μ±κ³΅μ μΌλ‘ Instructor object λ₯Ό μ±κ³΅μ μΌλ‘ κ°μ Έμ¨ κ²μ λ³Ό μ μλ€.
More on mappedBy

mappedBy μ λμ λ°©μμ λνμ¬ μμΈνκ² μμ보μ.
mappedBy λ₯Ό μ¬μ©νκ² λλ©΄, Hibernate λ λ€μκ³Ό κ°μ΄ λμνλ€.
InstructorDetailclass κ° μ°κ΄κ΄κ³μ μ£ΌμΈμ΄ μλλΌλ κ±Έ μΈμmappedBy = "instructorDetail"λΌκ³ νμΌλκΉ,Instructorclass μμμinstructorDetailλΌλ field λ₯Ό κ²μ- ν΄λΉ field μλ
@JoinColumn(name = "instructor_detail_id")κ° λΆμ΄μκΈ° λλ¬Έμ, Hibernateλ βμ, μ€μ FK λinstructorν μ΄λΈμ μꡬλβλΌκ³ νλ¨- λ°λΌμ Hibernateλ
InstructorDetailν μ΄λΈμλ μ무 μΈλ ν€λ λ§λ€μ§ μμ, λ¨μν mapping λ§ μ°Έμ‘°
κ²°κ³Όμ μΌλ‘ mappedBy λ Hibernate μκ² βFK λ μ΄μͺ½λ§κ³ μ μͺ½μ μμ΄, λ κ·Έλ₯ μ°Έκ³ λ§ νλκ±°μΌβλΌκ³ μλ €μ£Όλ μν μ΄κ³ , Hibernate λ μ£ΌμΈ μͺ½ enitity μμ FK μ 보(@JoinColumn)λ₯Ό μ°Ύμ μ¬μ©νλ€.
One-to-One Mapping Bi-Directional - Test (Delete)
μ΄λ²μλ Delete λ₯Ό ν΅νμ¬ Bi-Directional λ₯Ό test ν΄λ³΄μ.
@Override
@Transactional
public void deleteInstructorDetailById(int theId) {
InstructorDetail tempInstructorDetail = entityManager.find(InstructorDetail.class, theId);
entityManager.remove(tempInstructorDetail);
}μμ κ°μ΄ AppDAOImpl μ method λ₯Ό μΆκ°νκ³ ,
private void deleteInstrcutorDetail(AppDAO appDAO) {
int theId = 2;
System.out.println("Deleting instructor detail id: " + theId);
appDAO.deleteInstructorDetailById(theId);
System.out.println("Done!");
}Main App μμλ method λ₯Ό μΆκ°νμ¬ test ν΄λ³΄μ.
μμμ InstructorDetail entity class μ Instructor field μλ Cascading option μ ALL λ‘ κ±Έμ΄μ£ΌμμΌλ, InstructorDetail μ delete νλ©΄ κ·Έ μμ
μ΄ Instructor μλ νλ¬κ° λͺ¨λ delete μ΄ λ κ²μ΄λ€. Main App μ μ€ννμ¬ κ²°κ³Όλ₯Ό νμΈνμ.

μ±κ³΅μ μΌλ‘ μ€νλ κ²μ λ³Ό μ μλ€.
One-to-One Mapping Bi-Directional - Test (Only delete Detail)
κ·ΈλΌ One-to-One Mapping Bi-Direction μ μν©μμ, μ€μ§ InstructorDetail λ§ μμ νκ³ μΆμ λμλ μ΄λ»κ² ν΄μΌ ν κΉ?
μ°μ λ§λ‘ μ€λͺ
ν΄λ³΄λ©΄ λ€μκ³Ό κ°λ€. λ¨Όμ InstructorDetail μ instructor field μ μ€μ ν Cascading option μ μ‘°μ ν΄μΌ νλ€. μλμ κ°μ΄ ALL μμ CascadeType.REMOVE λ§ λΉΌκ³ μ λΆ λ€ λ£μ΄μ£Όλ©΄ λ κ²μ΄λ€.
@OneToOne(mappedBy = "instructorDetail", cascade = {CascadeType.DETACH, CascadeType.MERGE, CascadeType.PERSIST, CascadeType.REFRESH})
private Instructor instructor;κ·Έλ¬λ μμ§ Instructor object μ instructorDetail field κ° InstructorDetail μ id field λ₯Ό μ°Έμ‘°νκ³ μκΈ° λλ¬Έμ InstructorDetail object λ₯Ό λ¨Όμ delete ν κ²½μ°,

μμ κ°μ΄ λ€λ₯Έ exception μ λ°μμν€μ§λ μμΌλ Hibernate κ° SELECT query λ§ μ€νν λΏ, DELETE query λ λ΄λΆμ μΌλ‘ μ€νμ‘°μ°¨ νμ§ μλλ€.
μ΄μ λ JPA μ Persistence Context μ κ΄λ¦¬ λ°©μκ³Ό μ°κ΄κ΄κ³μ μμ κΆ κ°λ λλ¬Έμ΄λ€.
μ무리 Bi-Directional μ΄λΌκ³ νλλΌλ mappedBy λ‘ κ΄λ¦¬λλ μͺ½μ Non-Owning Side μ΄λ©°, μ΄λ λ¨μν μ°κ΄κ΄κ³μμ Read-Only View μΌ λΏμ΄λ©°, λ³κ²½ μ¬νμ΄ DB μ μ§μ λ°μλμ§ μλλ€.
λ°λΌμ InstructorDetail λ§ delete νκΈ° μνμ¬λ ν΄λΉ object λ₯Ό μμ ν λ
립μ object λ‘ λλμ΄μΌ νλ€. μ¦, λ€λ₯Έ object λ‘λΆν° μ°Έμ‘°λ₯Ό λ°λ μνμ΄λ©΄ μ λλ€.
@Override
@Transactional
public void deleteInstructorDetailById(int theId) {
...
tempInstructorDetail.getInstructor().setInstructorDetail(null);
...
}κ·Έλ λ€λ©΄ μμ κ°μ΄ InstructorDetail μ associate λ Instructor μ μ°Έμ‘°λ₯Ό κ°μ λ‘ null λ‘ λ°κΎΈμ΄ Bi-Directional κ΄κ³λ₯Ό λμ΄μΌ νλ€. μ΄λ κ² νκ³ λ€μ test ν΄λ³΄λ©΄,

Hibernate κ° null λ‘ λ°κΎΈλ query λ₯Ό μ€ννκ³ , μλμ DELETE query λ μ μμ μΌλ‘ λ³΄λΈ κ²μ νμΈν μ μλ€.


μ€μ DB μμλ Instructor μ μ μ§λμ΄ μλ κ²μ λ³Ό μ μλ€.