길지 않으니 이 글을 먼저 읽어보길 권장한다!!!
전 시간과 같은 테이블과 엔티티를 사용하도록 하겠다!!!
양방향 연관관계 매핑
양방향 연관관계 매핑을 할 때는 주인을 반드시 정해줘야 한다. 주인이란 무엇일까?
Student ↔ Club의 양방향 관계 매핑 실습을 해보면서 알아보자!!!
현재 Student → Club은 성립되고 있으므로, Club → Student만 만족시키면 Student ↔ Club가 성립될 것이다.
따라서 Club Entity를 고쳐야한다.
Club
package hellojpa;
import lombok.Getter;
import lombok.Setter;
import javax.persistence.*;
import java.util.ArrayList;
import java.util.List;
@Entity
@Setter
@Getter
public class Club {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY, generator = "CLUB_GENERATOR")
private Long id;
private String name;
private String description;
@OneToMany(fetch = FetchType.LAZY, mappedBy = "club")
private List<Student> students = new ArrayList<>();
}
students라는 필드가 추가됐다!! 하나씩 살펴보자~~~
Club:Student = 1:N이 성립한다. 즉, Club → Student는 1 → N인데, 이런 상황에서는 OneToMany 어노테이션을 사용하여 관계를 매핑해준다.
(Tip: 반대의 상황에서는 ManyToOne을 1:1의 상황에서는 OneToOne을 사용해주자!!)
[fetch는 관계설정과는 상관없는 옵션이므로 건너뛰겠다. 궁금하면 검색!!!]
중요한 옵션은 mappedBy이다. 자바 문서를 참고해보면 mappedBy는 양방향 매핑 시 종(주가 아닌) 쪽에 반드시 지정해야한다고 돼있다.
***** 그렇다면 주와 종은 어떻게 결정할까? 객체의 관점에서 외래키가 있는 컬럼의 Entity가 주가 된다!!! *****
(Tip: mappedBy는 OneToMany와 OneToOne에서만 지정 가능하다!! 즉 1:N의 관계에서는 N에 해당하는 Entity가 반드시 주가 된다.
왜냐하면 1:N의 관계에서는 N 테이블에 반드시 외래키 컬럼이 존재한다. 따라서 Java에서도 mappedBy 옵션을 OneToMany에서만 사용가능하게 한 것이다.)
mappedBy 옵션의 value로 들어가는 값은 Student Entity와 함께 봐야 알 수 있다.
Student Entity
package hellojpa;
import lombok.Getter;
import lombok.Setter;
import javax.persistence.*;
@Getter
@Setter
@Entity
@Table(name = "STUDENT")
public class Student {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY, generator = "STUDENT_GENERATOR")
private Long id;
private int age;
private String name;
@ManyToOne
@JoinColumn(name = "club")
private Club club;
}
주 Entity인 Student에서는 Club type의 변수가 있고, 변수명은 club이다.
아까 Club에서 봤던 students의 mappedBy 옵션으로 club을 넣었었는데, 이 변수명을 넣어준 것이다.
mappedBy의 옵션의 value로는 양방향 관계의 주 Entity에서 선언된 변수명을 넣어주면 된다.
이제 나머지는 JPA가 알아서 처리해줄 것이다. club.getStudents()를 호출해서 정상작동하는지 확인해보자!!
코드 확인해보기
package hellojpa;
import javax.persistence.EntityManager;
import javax.persistence.EntityManagerFactory;
import javax.persistence.EntityTransaction;
import javax.persistence.Persistence;
import java.util.List;
public class JpaMain {
public static void main(String[] args) {
//애플리케이션 로딩 시점에 DB당 딱 하나만 만들어야 하며, 애플리케이션 전체에서 공유한다.
EntityManagerFactory emf = Persistence.createEntityManagerFactory("hello");
//트랜잭션마다 EntityManager를 만들어줘야 한다.
EntityManager em = emf.createEntityManager(); // 고객요청 시마다 생성(쓰레드 간에 공유 X)
EntityTransaction tx = em.getTransaction();
tx.begin(); //트랜잭션 시작
try {
Club club = new Club();
club.setName("프로그래밍부");
club.setDescription("재밌게 같이 코딩해봐요~~~");
em.persist(club);
Student codeMania = new Student();
codeMania.setName("code-mania");
codeMania.setAge(21);
codeMania.setClub(club);
em.persist(codeMania);
Student codeLover = new Student();
codeLover.setName("code-lover");
codeLover.setAge(21);
codeLover.setClub(club);
em.persist(codeLover);
em.flush();
em.clear();
Club findClub = em.find(Club.class, club.getId());
List<Student> students = findClub.getStudents();
for(Student s:students) System.out.println(club.getName() + ": " + s.getName());
tx.commit();
} catch (Exception e) {
tx.rollback();
} finally {
em.close();
}
emf.close();
}
}
양방향 관계가 잘 성립된 것을 확인해볼 수 있다!!! 너무 잘 동작한다!!! 너무 행복하다!!!!!
나의 경우 Boot를 섞지 않은 순수 JPA 코드이니, 이 점은 참고하자~~~~
(참고로 코드 중간에 em.flush()와 em.clear()가 있다. 이는 쿼리를 모아서 DB에 날리고, 1차 캐시를 지우는 것이다~~ 잘 모르겠다면 검색해보긔~~~)
'JPA > 양방향연관관계' 카테고리의 다른 글
N:M(다 대 다) 매핑 4: 양방향 연관관계 편의 메서드 (0) | 2021.08.14 |
---|---|
N:M(다 대 다) 매핑 3: 매핑테이블을 엔티티로 만들기 (0) | 2021.05.22 |
N:M(다 대 다) 매핑 2: @ManyToMany와 @JoinTable (0) | 2021.05.21 |
N:M(다 대 다) 매핑 1: 매핑테이블 (0) | 2021.05.20 |
DB와 객체의 양방향 연관관계 차이 알아보기 (0) | 2021.03.10 |