[JPA] 연관관계 매핑 - 일대다 ( @OneToMany )
지난 포스팅에서 다대일 관계를 알아보았다.
다대일관계는 관계형DB와 패러다임이 일치하여 객체지향설계에서 가장 많이 사용하는 연관관계이다. 이에 반해, 일대다매핑은 거의 사용되지 않는다. 일대다 관계는 '일'이 '다'쪽을 참조하는 관계이다. 그러나 DB테이블은 '다'가 외래키를 갖고 있어, '다'가 '일'에 접근해야 한다. 이렇듯, 패러다임이 불일치하여 혼란을 줄 여지가 있어 일대다 매핑은 거의 사용되지 않는다.
게시판(일)이 댓글(다)에 접근하는 관계를 일대다로 표현할 수도 있지만 앞서 말했듯이, 혼란을 줄 여지가 있다.
게시판 클래스 ( 일 )
@Entity
@Data
public class Board {
@Id @GeneratedValue
@Column(name = "BOARD_ID")
Long id;
String title;
@Lob
String content;
@OneToMany
@JoinColumn(name = "BOARD_ID") // 외래키 객체를 직접 가지고 있음
List<Reply> replies = new ArrayList<>();
}
Board 클래스가 외래키 설정을 가지고 있다. 그러나 실제 프로그램이 실행되면 외래키는 댓글(REPLY) 테이블이 가져간다. 객체지향설계는 일대다 연관관계를 구현했지만 관계형DB는 다대일 관계이므로 JPA가 중간에 조정을 하게 된다.
댓글 클래스( 다 )
@Entity
@Data
public class Reply {
@Id @GeneratedValue
@Column(name = "REPLY_ID")
private Long id;
@Lob
private String content;
}
Main 클래스
public class Main {
public static void main(String[] args) {
EntityManagerFactory entityManagerFactory = Persistence.createEntityManagerFactory("h2");
EntityManager entityManager = entityManagerFactory.createEntityManager();
EntityTransaction tx = entityManager.getTransaction();
tx.begin();
try {
// 댓글 객체 생성
Reply reply1 = new Reply();
reply1.setContent("댓글1");
Reply reply2 = new Reply();
reply2.setContent("댓글2");
//게시판 객체 생성
Board board = new Board();
board.setTitle("게시판 제목");
board.setContent("게시판 내용");
board.getReplies().add(reply1);
board.getReplies().add(reply2);
// 영속화
entityManager.persist(board);
entityManager.persist(reply1);
entityManager.persist(reply2);
// 커밋
tx.commit();
}catch (Exception e) {
e.printStackTrace();
tx.rollback();
}finally {
entityManager.close();
}
}
}
게시판과 댓글 엔티티를 영속화하고 트랜잭션을 커밋해보았다. 그럼 어떤 로그가 출력되는지 확인해보자.
댓글 테이블에 UPDATE문이 실행되었음을 알 수 있다. 외래키는 댓글테이블에 있어야 하지만 일대다 관계라 댓글 엔티티에는 외래키설정이 없다. 그래서 JPA가 Board 클래스의 @OneToMany 어노테이션을 읽고 연관되어 있는 댓글 테이블에 UPDATE문을 실행하여 외래키를 생성해 준 것이다.
게시판 테이블
게시판 엔티티에는 외래키 설정이 있었지만 외래키가 사라져 있다.
댓글 테이블
반면, 댓글 테이블은 외래키 설정이 없었지만 외래키가 생성되어 있다. JPA는 객체지향과 관계형DB의 패러다임 불일치에도 자동으로 불일치를 해소한 것이다. JPA가 자동으로 해주긴 하지만 굳이 패러다임이 불일치한데 억지로 쓸 이유는 없다. 만약 일 쪽에서 다 쪽을 접근할 일이 있다면 다대일 관계를 양방향 관계로 만들면 된다. 일대다 관계는 혼란을 줄 여지가 있으므로 권장하지 않는다.
참고자료