본문 바로가기

부트캠프 TIL

22.12.28 JPA 방식 엔티티 간의 연관 관계 매핑

연관 관계 매핑은 참조하는 방향성을 기준으로 생각했을때 단방향 연관 관계와 양방향 연관 관계로 구분

-단방향 : (N:N과 같은 참조 객체 수 와는 다른 이야기)

Member 클래스에만  Order 참조 객체를 두고 Order 참조 가능. Order 클래스는 참조값 없어서 Member 정보 알 수 없음.

한쪽 클래스만 다른 쪽 클래스의 참조 정보를 가지고 있는 관계를 단방향 연관 관계

-양방향 : 

두 클래스가 모두 서로의 객체를 참조할 수 있으므로, Member는 Order 정보를 알 수 있고, Order는 Member 정보를 알 수 있음.

양쪽 클래스가 서로의 참조 정보를 가지고 있는 관계를 양방향 연관 관계

 

(JPA는 단방향 연관 관계와 양방향 연관 관계를 모두 지원하는 반면, Spring Data JDBC는 단방향 연관 관계만 지원)

 

엔티티 간에 참조할 수 있는 객체의 수에 따라서 일대다(1:N), 다대일(N:1), 다대다(N:N), 일대일(1:1)의 연관 관계로 구분

-1:N관계   :

일(1)에 해당하는 클래스가 다(N)에 해당하는 객체를 참조할 수 있는 관계

한명의 회원Member이 여러 건의 주문Order을 할 수 있으므로 Member와 Order는 1:N 관계

 

만약 1인 Member만 다에 해당하는 List<Order> 객체를 참조할 수 있으면 단방향

일대다 단방향 매핑은 잘 사용하지 않음.

(테이블 간의 관계에서는 일대다 중에서 ‘다’에 해당하는 테이블에서 ‘일’에 해당하는 테이블의 기본키를 외래키로 가짐

ORDERS 테이블이 MEMBER 테이블의 기본키인 member_id를 외래키로 가짐

위의 일대다 단방향 매핑에선 Order 클래스가 ‘테이블 관계에서 외래키에 해당하는 MEMBER 클래스의 참조값’을 가지고 있지 않기때문에 일반적인 테이블 간의 관계를 정상적으로 표현하지 못함.

Order 클래스의 정보를 테이블에 저장하더라도 외래키에 해당하는 MEMBER 클래스의 memberId 값이 없는채로 저장)

(다대일 단방향 매핑을 먼저 한 후에 필요한 경우, 일대다 단방향 매핑을 추가해서 양방향 연관 관계를 만드는 것이 일반적)

 

-N:1관계   :  (가장 기본으로 사용)

다(N)에 해당하는 클래스가 일(1)에 해당하는 객체를 참조할 수 있는 관계

 

다대일 단방향 매핑은 ORDERS 테이블이 MEMBER 테이블의 member_id를 외래키로 가지듯이 Order 클래스가 Member 객체를 외래키처럼 가지고 있음.

다(N)에 해당하는 Order 클래스에 추가

    @ManyToOne
    @JoinColumn(name = "MEMBER_ID") //ORDERS 테이블에서 외래키에 해당하는 컬럼명
    private Member member;

    public void addMember(Member member) {
        this.member = member;
    }

 @JoinColumn(name = "MEMBER_ID") //ORDERS 테이블에서 외래키에 해당하는 컬럼명

findOrder.getMember().getMemberId()와 같이 객체를 통해 다른 객체의 정보를 얻을 수 있는 것을 객체 그래프 탐색

다대일 관계에서는 일(1)에 해당하는 객체의 정보를 얻을 수 있음

 

회원 입장에서는 내가 주문한 주문의 목록을 확인할 수 있어야 할텐데 다대일 매핑만으로는 member 객체를 통해 내가 주문한 주문 정보인 order 객체들을 조회할 수 없음 ->다대일 매핑이 되어 있는 상태에서 일대다 매핑을 추가해 양방향 관계를 만들어줘

 

일(1)에 해당하는 Member 클래스에 추가

    @OneToMany(mappedBy = "member") //다(N)에 해당하는 클래스(order)에서 외래키의 역할을 하는 필드
    private List<Order> orders = new ArrayList<>();
    
    public void addOrder(Order order) {
        orders.add(order);
    }

 

일대다 단방향 매핑의 경우에는 mappedBy 애트리뷰트의 값이 필요하지 않음.

mappedBy 는 참조할 대상이 있어야 하는데 일대다 단방향 매핑의 경우 참조할 대상이 없으니까.

@OneToMany(mappedBy = "member")  //다(N)에 해당하는 클래스(order)에서 외래키의 역할을 하는 필드 "member"

 

Configuration 클래스에서

일대다 연관관계 매핑을 추가하여 주문 정보를 조회

        tx.begin();
        Member member = new Member("hgd@gmail.com", "Hong Gil Dong",
                "010-1111-1111");
        Order order = new Order();

        member.addOrder(order); 
        order.addMember(member); 

        em.persist(member);   
        em.persist(order);   

        tx.commit();

        Member findMember = em.find(Member.class, 1L);
        //주문한 회원의 회원 정보를 통해 주문 정보를 가져올 수 있음
        findMember
                .getOrders()
                .stream()
                .forEach(findOrder -> {
                    System.out.println("findOrder: " +
                            findOrder.getOrderId() + ", "
                            + findOrder.getOrderStatus());
                });

 

-N:N관계   :

하나의 주문에 여러개의 커피가 속할 수 있고, 하나의 커피는 여러 주문에 속할 수 있으니 다대다 관계

테이블 설계 시, 다대다의 관계는 중간에 테이블을 하나 추가해서 두 개의 일대다 관계를 만들어주는 것이 일반적

다대다 관계에 있는 ORDERS 테이블과 COFFEE 테이블 사이에 ORDER_COFFEE 테이블을 두고 두 개의 1대 다 관계로 설계 (ORDER_COFFEE 테이블은 ORDERS 테이블의 외래키와 COFFEE 테이블의 외래키를 가짐)

일대다 단방향 매핑은 외래키를 포함하지 않기때문에 자주 사용되지 않는 매핑 방법이기에 두 개의 다대일 매핑이 필요.

/여기까지는 두개의 다대일 단방향.

 

그리고 나서 현실적으로 다대일 매핑을 통해 객체 그래프 탐색으로 원하는 객체를 조회할 수 없다면 그때 일대다 양방향 매핑을 추가.

 

-1:1관계   :

일대일 연관 관계 매핑, 양방향 매핑을 추가하는 방법은 다대일 단방향, 양방향 연관 관계 매핑 방법과 동일.

@OneToOne 애너테이션을 사용