Jpa

다양한 연관관계 매핑

k0o9 2021. 1. 10. 18:51

참고 이글은 자바 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 Entity

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을 이용해 외래키와 매핑한다. 식별관계와 달리 부모 테이블의 기본키를 받아와서 단순히 외래키로만 사용하는 것을 비식별 관계라고 한다.