[JPA] 연관관계 매핑 - 일대일 ( @OneToOne )
일대일관계는 주테이블이 외래키를 가지고 있느냐, 대상테이블이 외래키를 갖고 있느냐에 따라 성격이 달라진다. 회원과 라커는 일대일 관계이다. 회원이 있어도 라커는 없어도 된다. 반대로 회원이 없는데 라커가 있으면 안 된다.
이처럼 주도권을 가지고 있는 객체의 테이블을 주테이블이라고 한다.
주테이블이 외래키(FK)를 가지고 있으면 객체지향과 패러다임이 일치한다. 회원테이블이 외래키를 가지므로 회원테이블에서 라커테이블에 접근한다. 그러나 한 가지 문제가 있다. 회원만 있고 라커가 없다고 가정해보자. 라커가 없으면 FK는 NULL값이 된다. FK에 NULL값이 들어갈 수는 있지만 DB관점에서 좋지 못하다.
그럼 반대로 대상테이블에 외래키(FK)가 있는 경우를 생각해보자.
회원과 라커는 양방향 관계가 된다. 라커에 외래키 설정이 있어야 하기 때문이다. 이 구조의 좋은점은 외래키에 NULL값이 들어가지 않는다. 라커는 회원이 없으면 존재하지 않는다. 그러므로 회원 외래키에 NULL값이 들어갈 경우가 없다. 또한 좋은점은 대상테이블은 일대일 관계에서 다대일 관계로 바뀔 가능성이 높다. 회원이 여러 개의 라커를 사용하게 될 가능성이 높다. 반면 라커 하나를 여러 회원이 사용하는 경우는 적다. 이렇듯, 대상테이블은 '일'에서 '다'로 바뀔 가능성이 높다. '다대일'관계에서 '다'쪽이 외래키를 가지고 있는 것은 관계형DB의 규칙이다.
정리하면, 주테이블이 외래키를 가지면 객체지향패러다임과 일치한다는 장점이 있지만 DB관점에서는 좋지 못하다. 대상테이블이 외래키를 가지면 객체지향 패러다임과는 불일치하지만 DB관점에서는 좋다. 그러므로 어디에 외래키를 둘 것인가는 실무상황에 따라 달리하면 된다.
코드구현
회원 엔티티 ( 주테이블 )
@Entity
@Data
public class Member {
@Id @GeneratedValue
@Column(name = "MEMBER_ID")
private Long id;
private String name;
@OneToOne(mappedBy = "member")
private Locker locker;
}
라커 엔티티 ( 대상테이블 )
@Entity
@Data
public class Locker {
@Id @GeneratedValue
@Column(name = "LOCKER_IO")
private Long id;
@OneToOne
@JoinColumn(name = "MEMBER_ID") // 대상테이블에 외래키
private Member member;
}
주테이블에 외래키를 두고 싶으면 @JoinColumn을 주테이블에 두면 된다.
참고자료