16. 다양한 연관관계 매핑(2)
16. 다양한 연관관계 매핑(2)
3. 일대일[1:1]
일대일 관계는 양쪽이 서로 하나의 관계만 가진다. 예를 들어 회원은 하나의 사물함만 사용하고 사물함도 하나의 회원에 의해서만 사용된다.
일대일 관계는 다음과 같은 특징이 있다.
- 일대일 관계는 그 반대도 일대일 관계다.
- 테이블 관계에서 일대다. 다대일은 항상 다(N)쪽이 외래 키를 가진다. 반면에 일대일 관계는 주 테이블이나 대상 테이블 둘 중 어느 곳이나 외래 키를 가질 수 있다.
테이블은 주 테이블이든 대상 테이블이든 외래 키 하나만 있으면 양쪽으로 조회할 수 있다. 그리고 일대일 관계는 그 반대쪽도 일대일 관계다. 따라서 일대일 관계는 주 테이블이나 대상 테이블 중에 누가 외래 키를 가질지 선택해야 한다.
주 테이블에 외래 키
주 객체가 대상 객체를 참조하는 것처럼 주 테이블에 외래 키를 두고 대상 테이블을 참조한다. 외래 키를 객체 참조와 비슷하게 사용할 수 있어서 객체지향 개발자들이 선호한다. 이 방법의 장점은 주 테이블이 외래 키를 가지고 있으므로 주 테이블만 확인해도 대상 테이블과 연관관계가 있는지 알 수 있다.
대상 테이블에 외래 키
전통적인 데이터베이스 개발자들은 보통 대상 테이블에 외래 키를 두는 것을 선호한다. 이 방법의 장점은 테이블 관계를 일대일에서 일대다로 변경할 때 테이블 구조를 그대로 유지할 수 있다.
이제 모든 일대일 관계를 하나씩 살펴보자.
1. 주 테이블에 외래 키
일대일 관계를 구성할 때 객체지향 개발자들은 주 테이블에 외래 키가 있는 것을 선호한다. JPA도 주 테이블에 외래 키가 있으면 좀 더 편리하게 매핑할 수 있다. 주 테이블에 외래 키가 있는 단방향 관계를 먼저 살펴보고 양방향 관계도 살펴보자.
단방향
아래 그림과 예제 코드를 통해 회원과 사물함의 일대일 단방향 관계를 알아보자. MEMBER가 주 테이블이고 LOCKER는 대상 테이블이다.
@Entity
public class Member {
@Id @GenertaedValue
@Column(name = "MEMBER_ID")
private Long id;
private String username;
@OneToOne
@JoinColumn(name = "LOCKER_ID")
private Locker locker;
...
}
@Entity
public class Locker {
@Id @GeneratedValue
@Column(name = "LOCKER_ID")
private Long id;
private String name;
...
}
일대일 관계이므로 객체 매핑은 @OneToOne을 사용했고 데이터베이스에는 LOCKER_ID 외래 키에 유니크 제약 조건(UNI)을 추가했다. 참고로 이 관계는 다대일 단방향(@ManyToOne)과 거의 비슷하다.
다음으로 반대 방향을 추가해서 일대일 양방향 관계로 만들어보자.
양방향
아래 그림과 예제 코드를 통해 양방향 관계를 알아보자.
@Entity
public class Member {
@Id @GenertaedValue
@Column(name = "MEMBER_ID")
private Long id;
private String username;
@OneToOne
@JoinColumn(name = "LOCKER_ID")
private Locker locker;
...
}
@Entity
public class Locker {
@Id @GeneratedValue
@Column(name = "LOCKER_ID")
private Long id;
private String name;
@OneToOne(mappedBy = "locker")
private Member member;
...
}
양방향이므로 연관관계의 주인을 정해야 한다. MEMBER 테이블이 외래 키를 가지고 있으므로 MEMBER 엔티티에 있는 MEMBER.locker가 연관관계의 주인이다. 따라서 반대 매핑인 사물함의 Locker.member는 mappedBy를 선언해서 연관관계의 주인이 아니라고 설정했다.
2. 대상 테이블에 외래 키
이번에는 대상 테이블에 외래 키가 있는 일대일 관계를 알아보자.
단방향
아래 그림을 보자. 일대일 관계 중 대상 테이블에 외래 키가 있는 단방향 관계는 JPA에서 지원하지 않는다. 그리고 이런 모양으로 매핑할 수 있는 방법도 없다. 이때는 단방향 관계를 Locker에서 Member 방향으로 수정하거나, 양방향 관계로 만들고 Locker를 연관관계의 주인으로 설정해야 한다. 이 방향은 다음 양방향에서 알아보자.
참고로 JPA2.0부터 일대다 단방향 관계에서 대상 테이블에 외래 키가 있는 매핑을 허용했다. 하지만 일대일 단방향은 이런 매핑을 허용하지 않는다.
양방향
아래 그림과 예제를 통해 대상 테이블에 외래 키가 있는 양방향 관계를 알아보자.
@Entity
public class Member {
@Id @GenertaedValue
@Column(name = "MEMBER_ID")
private Long id;
private String username;
@OneToOne(mappedBy = "member")
private Locker locker;
...
}
@Entity
public class Locker {
@Id @GeneratedValue
@Column(name = "LOCKER_ID")
private Long id;
private String name;
@JoinColumn(name = "MEMBER_ID")
private Member member;
...
}
일대일 매핑에서 대상 테이블에 외래 키를 두고 싶으면 이렇게 양방향으로 매핑한다. 주 엔티티인 Member 엔티티 대신에 대상 엔티티인 Locker를 연관관계의 주인으로 만들어서 LOCKER 테이블의 외래 키를 관리하도록 했다.
프록시를 사용할 때 외래 키를 직접 관리하지 않는 일대일 관계는 지연 로딩으로 설정해도 즉시 로딩된다. 예를 들어 방금 본 예제에서 Locker.member는 지연 로딩할 수 있지만, Member.locker는 지연 로딩으로 설정해도 즉시 로딩된다. 이것은 프록시의 한계 때문에 발생하는 문제인데 프록시 대신에 bytecode.instrumentation을 사용하면 해결할 수 있다.
참고
- 자바 ORM 표준 JPA 프로그래밍
Author And Source
이 문제에 관하여(16. 다양한 연관관계 매핑(2)), 우리는 이곳에서 더 많은 자료를 발견하고 링크를 클릭하여 보았다 https://velog.io/@jsj3282/16.-다양한-연관관계-매핑2저자 귀속: 원작자 정보가 원작자 URL에 포함되어 있으며 저작권은 원작자 소유입니다.
우수한 개발자 콘텐츠 발견에 전념 (Collection and Share based on the CC Protocol.)