다양한 연관관계 매핑
참고 이글은 자바 ORM 표준 JPA프로그래밍을 읽고 정리한 글입니다.
엔티티와 연관관계를 매핑할 때는 3가지를 고려한다.
1.다중성
2.방향성
3.연관관계의 주인
다중성
-다대일
-일대다
-일대일
-다대다
왼쪽을 연관관계의 주인으로 정함. 다중성을 판단하기 어려울때는 반대방향을 생각해보면 된다. 반대방향이 일대다라면 자신은 그의 반대인 일대다이다.
다대일
반대방향:일대다
연관관계의주인:다
위의 사진은 회원과 팀을 다대일 단방향으로 구성해둔것이다. 위를 보면 Member엔티티는 team으로 Team엔티티에 참조할 수 없지만 그 역은 성립하지 않는다.
실선이 연관관계의 주인이고 점선이 연관관계의 주인이 아니다. JPA는 외래키를 관리할때 연관관계의 주인만 사용하기 때문에 Team.mebers는 조회를 위한 JPQL이나 객체 그래프를 탐색할때만 사용한다.
양쪽을 항상 서로 참조해야한다.
일대다
반대방향:다대일
연관관계의주인:일
엔티티를 하나 이상 참조할 수 있으므로 자바 컬렉션인 List,Set,Map 중에 하나를 사용해야한다.
외래키는 다쪽에 있지만 연관관계의 주인은 일에 위치한다. 객체와 테이블의 차이때문에 반대편 테이블의 외래키를 관리하는 특이한 모습을 보인다.
일대다 단방향 관계를 매핑할때는 항상 @JoinColumn을 명시해야한다. 그렇게 하지 않으면 조인테이블 전략을 기본으로 사용해서 매핑한다.
-외래키가 다른 테이블에 있을때의 단점
본인 테이블에 외래키가 있으면 엔티티의 저장과 연관관계 처리를 SQL 문 한번에 끝낼 수 있지만, 다른 테이블에 외래 키가 있으면 연관관계 처리를 위한 UPDATE SQL문을 추가로 실행해야한다.
-> 일대다 단방향 매핑보다는 다대일 양방향 매핑을 권장
실재로 존재하지 않는매핑이다. -> 다대일 양방향 매핑을 사용.
관계형 데이터베이스에서 @OneToMany는 연관관계의 주인이 될수 없음 -> 항상 다쪽에 외래키가 있기때문
완전히 구현이 불가능한 것은 아니다.
->일대다 단방향 매핑 반대편에 같은 외래키를 사용하는 다대일 단방향 매핑을 읽기전용으로 하나 추가.
-> 일대다 양방향 매핑보다는 다대일 양방향 매핑을 권장
일대일
반대:일대일
외래키:둘중 어느곳이나 가질 수 있다.
->둘중 누가 외래키를 가질지 선택해야한다.
-주테이블에 외래키
:객체 지향 개발자들 선호
다대일 단방향과 거의 비슷.
양방향이므로 연관관계의 주인을 정해야한다. 외래키를 가진쪽이 연관관계의 주인이므로 Member.locker가 연관관계의 주인.
-대상테이블에 외래 키
JPA에서는 일대일관계 중 대상 테이블에 외래키가 있는 단방향 관계는 지원하지 않는다.
일대일 매핑에서 대상테이블에 외래키를 두고 싶을대 사용하는 방법.
주테이블 양방향 매핑이랑 방법이 같음
다대다
관계형 데이터베이스에서 정규화된 테이블 2개로 다대다 관계를 표현할 수 없다. 그래서 중간에 연결테이블을 추가해서 사용한다. 그에 반해 객체는 2개로 다대다관계를 만들 수 있다.
@ManyToMany와 @JoinTable을 사용해서 연결테이블을 바로 매핑. 연결할때 Member_Product의 엔티티 없이 매핑이 가능하다.
양방향의 경우 원하는 곳에 연관관계의 주인을 지정.
-한계
보통 연결테이블에 주문수량 컬럼이나 주문한 날짜 같은 컬럼이 필요한데 이러한 컬럼을 추가할경우 주문엔티티나 상품엔티티에 추가한 컬럼을 매핑할 수 없기에 @ManyToMany 사용 x
->한계를 극복하기 위해 연결테이블을 엔티티로 사용해서 컬럼을 추가한다.
@ManyToMany -> OneToMany + ManyToOne 으로 쪼개서 사용.
Member_Product를 보면 MEMBER_ID 와 PRODUCT_ID로 이루어진 복합 기본 키를 가지고 있다. JPA에서 복합키를 사용하려면 별도의 식별자 클래스를 만들어야 한다. 엔티티에 @IdClass를 사용해서 식별자 클래스를 지정하면 된다.
-복합키를 위한 식별자 클래스 특징
:복합 키는 별도의 식별자 클래스를 만들어야 한다.
:Serializable을 구현해야 한다.
:equals와 hashCode 메소드를 구현해야 한다.
:기본 생성자가 있어야 한다.
:식별자 클래스는 public이어야 한다.
:@IdClass를 사용하는 방법 외에 @EmbeddedId를 사용하는 방법도 있다.
식별관계
부모테이블의 키를 받아서 자신의 기본키 +외래키로 사용하는 것.
복합키를 사용하지 않고 다대다 관계를 구성하는 방법을 알아보도록 하겠다.
다대다 : 기본키 사용 방법
-추천하는 기본키 생성 전략
:데이터베이스에서 자동으로 생성하는 대리 키를 Long값으로 사용.
ㄴ 간편하고 거의 영구적으로 사용가능하며 비즈니스에 의존하지 않는다.
자 이제 MEMBER_PRODUCT를 ORDER엔티티로 바꾼후 아까처럼 복합키로 사용하지 않고 기본키로 ORDER_ID를 사용하고 MEBER_ID 와 PRODUCT_ID는 외래키로 사용하겠다.
@Entity
@Table(name = "ORDERS")
public class Order {
@Id @GeneratedValue
@Column(name = "ORDER_ID")
private Long id;
@ManyToOne
@JoinColumn(name = "MEMBER_ID")
private Member member; //주문 회원
@OneToMany(mappedBy = "order")
private List<OrderItem> orderItems = new ArrayList<OrderItem>();
@OneToOne
@JoinColumn(name = "DELIVERY_ID")
private Delivery delivery; //배송정보
private Date orderDate; //주문시간
@Enumerated(EnumType.STRING)
private OrderStatus status;//주문상태
JoinColum을 이용해 외래키와 매핑한다. 식별관계와 달리 부모 테이블의 기본키를 받아와서 단순히 외래키로만 사용하는 것을 비식별 관계라고 한다.