학급 반 - 학생 관계를 OneToMany로 표현
OneToMany 단방향
class entity는 반에 속해있는 학생들(Student Entity)을 참조할 수 있다.
@Entity
public class ClassRoom {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private int id;
private String name;
@OneToMany
private List<Student> students;
}
@Entity
public class Student {
private String name;
@Id
@GeneratedValue(strategy = jakarta.persistence.GenerationType.IDENTITY)
private int id;
}
1. 테이블 생성
한번 실행해서, 테이블이 제대로 생성되었는지 확인해보자!
public class Test {
public static void main(String[] args) {
Map<String, String> props = new HashMap();
props.put("hibernate.show_sql", "true");
props.put("hibernate.hbm2ddl.auto", "update"); // create (항상 새로 만든다), update ( 없으면 만들고, 있으면 변경되어야 하면 변경 )
// hbm2ddl <= Hibernate Mapping to(2) DDL
EntityManagerFactory emf =
new HibernatePersistenceProvider().createContainerEntityManagerFactory(
new MyPersistenceUnitInfo(), props
);
EntityManager em = emf.createEntityManager();
try {
em.getTransaction().begin();
// 테이블 생성
{
}
em.getTransaction().commit();
}finally {
em.close();
}
}
}
테이블이 생성된 것을 확인
ClassRoom과 Student 테이블뿐만 아니라, 둘 사이의 연관관계를 나타내는 ClassRoom_Student 테이블도 생긴 것을 확인할 수 있었다.
2. 각각의 Entity 생성해보기
// #2
// Class Entity 1개 생성
{
ClassRoom c = new ClassRoom();
c.setName("반1");
em.persist(c);
}
// #3
// Student Entity 2개 생성
{
Student s1 = new Student();
s1.setName("학생1");
Student s2 = new Student();
s2.setName("학생2");
em.persist(s1);
em.persist(s2);
}
ClassRoom 확인
Student 확인
ClassRoom_Student 확인
아직 3개의 Entity에 대해 연관관계를 적용하지 않았기 때문에 , ClassRoom_Student 테이블은 데이터가 없다.
3. 각각 Entity 생성해서, 연결하기
{
ClassRoom c = new ClassRoom();
c.setName("반1");
Student s1 = new Student();
s1.setName("학생1");
Student s2 = new Student();
s2.setName("학생2");
c.setStudents(List.of(s1,s2));
em.persist(c);
em.persist(s1);
em.persist(s2);
}
로그 확인
ClassRoom_Student
각각의 엔티티가 잘 연결된 것을 확인할 수 있다.
4. ClassRoom만 Persist 적용한다면?
{
ClassRoom c = new ClassRoom();
c.setName("반1");
Student s1 = new Student();
s1.setName("학생1");
Student s2 = new Student();
s2.setName("학생2");
c.setStudents(List.of(s1,s2));
em.persist(c);
}
아래와 같이 에러가 발생하는데, 그 이유는 DB에 ClassRoom Entity를 저장하려고 하는데, ClassRoom Entity가 참조하고 있는 Student Entity들이 DB에 저장되어있지 않기 때문이다. 이를 위해서는 Student도 같이 저장하거나, cascade 옵션을 추가하여 연관된 객체는 같이 저장할 수 있게 하는 방법들이 있다.
5. ClassRoom 연관관계 cascade 옵션 추가하기
아래와 같이 옵션을 적용한 후 다시 시도해보자
@Entity
public class ClassRoom {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private int id;
private String name;
@OneToMany(cascade = CascadeType.PERSIST)
private List<Student> students;
}
결과
성공적으로 저장된 것을 확인할 수 있다.
6. ClassRoom만 조회하기
아래와 같이 ClassRoom만 조회한 후, 5초 뒤 참조하고 있는 Student를 출력하면 어떻게 될지 확인해 보자.
{
ClassRoom classRoom = em.find(ClassRoom.class, 1);
System.out.println(classRoom);
try{
Thread.sleep(5000);
} catch (Exception e) {
e.printStackTrace();
}
System.out.println(classRoom.getStudents());
}
결과
classRoom을 처음 조회했을 때는, ClassRoom만 조회하는 SQL 이 실행되는 것을 확인할 수 있었다.
그 후 5초 뒤, Student를 조회할 때 다시 Join SQL이 실행되어 연관된 Student들을 조회하였다.
그 이유는@OneToMany의 fetch 기본 값이 Lazy로 적용되어 있어, ClassRoom 조회한 후에 Student가 필요할 때 따로 조회해서 들고오는 것이었다.
7. ClassRoom 연관관계 FeatchType EAGER 로 적용하기
Student 참조를 EAGER로 조회하도록 설정한 후, 실행해보자
@Entity
public class ClassRoom {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private int id;
private String name;
@OneToMany(fetch = FetchType.EAGER)
private List<Student> students;
}
//조회 실행 코드
{
ClassRoom classRoom = em.find(ClassRoom.class, 1);
System.out.println(classRoom);
try{
Thread.sleep(5000);
} catch (Exception e) {
e.printStackTrace();
}
System.out.println(classRoom.getStudents());
}
로그
아래와 같이, 처음부터 join하여 ClassRoom과 참조하고 있는 Student 까지 모두 조회한다.
8. 기존의 ClassRoom Entity를 불러와서 Student 추가로 저장하기
ClassRoom classRoom = em.find(ClassRoom.class, 1L);
Student student = new Student();
student.setName("이길동");
classRoom.getStudents().add(student);
em.persist(classRoom);
위 처럼 기존의 ClassRoom을 가져온 후, 새로 Student를 추가하고 ClassRoom만 저장해도 새로운 Student도 저장된다.
그 이유는 이전에 ClassRoom에 cascade 옵션을 적용했기 때문이다.
로그
반대로, student만 저장해도 둘다 저장이 될까 ?
ClassRoom classRoom = em.find(ClassRoom.class, 1L);
Student student = new Student();
student.setName("이길동");
classRoom.getStudents().add(student);
em.persist(student);
저장이 되는 것을 확인할 수 있었다.
'개발일지' 카테고리의 다른 글
MongoDB Replica Set 구성 (0) | 2024.09.02 |
---|---|
미니프로젝트 회고 (0) | 2024.07.19 |
BastionHost를 이용한 EC2 SSH 접속 (0) | 2024.04.07 |
테스트 H2 DB DATEDIFF 메서드 안됨 (0) | 2024.02.07 |
[개발일지] 접속관련 FCM 메세지 전송 기준 개선 (0) | 2024.01.28 |
꾸준히 기록할 수 있는 사람이 되자 !