JPA를 다루다보면 까다로운게 한두군데가 아닌거 같다. 아직 JPA를 손쉽게 다루지 못해서 그러지만.. 하면 할 수록 어렵단 말이야..

그 중에서 오늘은 JPA에서 OneToOne 관계에 대해서 알아보려한다. JPA의 OneToOne 관계는 정말 까다롭다. OneToOne 관계로 설계할 때는 심히 많은 고민을 해보길 바란다. 정말로 OneToOne 관계를 해야 되나…말이다.

첫 번째 방법

아래의 코드는 OneToOne(양방향)의 첫 번째 방법이다.

@Entity
public class Content {

  @Id
  @GeneratedValue
  private Long id;

  private String title;

  @OneToOne(cascade = CascadeType.ALL, fetch = FetchType.LAZY, mappedBy = "content")
  @JoinColumn(name = "CONTENT_ID")
  private ContentDetail contentDetail;

  //기타 생략
}
@Entity
public class ContentDetail {

  @Id
  @GeneratedValue
  private Long id;

  private String text;

  @OneToOne(fetch = FetchType.LAZY)
  private Content content;

  //기타 생략
}

우리는 대략 이런 모델링을 했다고 가정하자. Content 엔티티가 부모측이고 ContentDetail가 자식측 이다. 이렇게 작성을 했을 때 스키마는 어떻게 작성 되나 살펴보자.

create table content (
  id bigint generated by default as identity,
  title varchar(255),
  primary key (id)
)

create table content_detail (
  id bigint generated by default as identity,
  text varchar(255),
  content_id bigint,
  primary key (id)
)

alter table content_detail
  add constraint FKkxm1ajimhk153isl1cnun1r4i
foreign key (content_id)
references content

대충 위와 같이 스키마가 나왔다. content에 ContentDetail은 연관관계의 주인이 아니기에 mappedBy로 설정하였다.
그리고 아래와 같이 저장을 해보자.

@Transactional
public void save(){
  ContentDetail contentDetail = new ContentDetail("content");
  Content content = new Content("title", contentDetail);
  contentDetail.setContents(content);
  final Content save = contentRepository.save(content);
  //생략
}

잘들어 간다. content 테이블에 먼저 insert 후에 content_detail 테이블에도 insert를 실행한다. 그러고 나서 해당하는 seq로 조회를 해보자.

public Content findOne(Long id) {
  final Content one = contentRepository.findOne(id);
  //생략
}

그리고나서 한번 실행된 쿼리문을 살펴보자.

select
  content0_.id as id1_0_0_,
  content0_.title as title2_0_0_
from
  content content0_
where
  content0_.id=?

select
  contentdet0_.id as id1_1_0_,
  contentdet0_.content_id as content_3_1_0_,
  contentdet0_.text as text2_1_0_
from
  content_detail contentdet0_
where
  contentdet0_.content_id=?