2023.06.22 코드스테이츠 51회차. ( 엔티티 간의 연관 관계 매핑 )

2023. 6. 22. 18:03Code

반응형

연관 관계 매핑

- 엔티티 클래스 간의 관계를 만들어즈는 것이 연관 관계 매핑 이다

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

 

 

단방향 연관 관계

 

- Member 클래스가 Order 객체를 원소로 포함하고 있는 List 객체를 가지고 있으므로, Order를 참조할 수 있다

그렇기에 Member는 Order의 정보를 알 수 있다

- 하지만 Order 클래스는 Member 클래스에 대한 참조 값이 없으므로 Order 입장에서는 Member 정보를 알 수 없다

 

 

- Order 클래스가 Member 객체를 가지고 있으므로, Member 클래스를 참조할 수 있다

그렇기에 Order는 Member의 정보를 알 수 있다

- 하지만 Member 클래스는 Order 클래스에 대한 참조 값이 없으므로 Member 입장에서는 Order 정보를 알 수 없다

 

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

 

 

 

 

양방향 연관 관계

- Member 클래스가 Order 객체를 원소로 포함하고 있는 List 객체를 가지고 있고, Order 클래스를 참조할 수 있다 

( Member는 Order의 정보를 알 수 있다 )

- Order 클래스 역시 Member 객체를 가지고 있으므로, Member 클래스를 참조할 수 있다

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

 

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

 

- JPA는 단방향 연관 관계와 양방향 연관 관계를 모두 지원하는 반면에 Spring Data JDBC는 단방향 연관 관계만 지원한다

 

 

 

일대다 단방향 연관 관계

일대다 단방향 연관 관계

- 일대다의 관계란 일(1)에 해당하는 클래스가 다(N)에 해당하는 객체를 참조할 수 있는 관계를 말한다.

- 한 명의 회원이 여러 건의 주문을 할 수 있으므로 Member와 Order는 일대다 관계이다

- Member만 List<Order> 객체를 참조할 수 있으므로 단방향 관계이다

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

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

 

 

 

MEMBER 테이블과 ORDERS 테이블의 관계

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

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

 

 

## 일대다 단방향 매핑 하나만 사용하는 경우는 드물고, 다대일 단방향 매핑을 먼저 한 후에 필요한 경우, 일대다 단방향 매핑을 추가해서 양방향 연관 관계를 만드는 것이 일반적이다

 

 

 

다대일 연관 관계

 

다대일 단방향 연관 관계

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

- 여러 건의 주문은 한 명의 회원에 속할 수 있으므로 Order와 Member는 다대일 관계이다

- Order만 Member 객체를 참조할 수 있으므로 단방향 관계이다

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

 

 

 

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

- 다대일의 연관관계 매핑에서는 (1), (2)와 같은 방법으로 매핑을 할 수 있다

- (1)과 같이 @ManyToOne 애너테이션으로 다대일의 관계를 명시한다

- (2)와 같이 @JoinColumn 애너테이션으로 ORDERS 테이블에서 외래키에 해당하는 열 이름을 적어준다

- 일반적으로 부모 테이블에서 기본키로 설정된 열 이름과 동일하게 외래키 열을 만드는데, 여기서는 MEMBER 테이블의 기본키 열 이름이 “MEMBER_ID” 이기 때문에 동일하게 적어주었다

- 다대일 단방향 연관 관계이기 때문에 (1), (2)와 같이 다(N) 쪽에서만 설정을 해주면 매핑 작업은 끝난다

- 주문을 하기 위해서는 회원 정보가 필요한데, (1)에서 회원 정보를 저장한다

- (1)에서 저장한 회원 정보의 주문 정보를 저장하기 위해서 (2)와 같이 order 객체에 member 객체를 추가한다

( order 객체에 추가된 member 객체는 외래키의 역할을 한다 )

## INSERT 쿼리문에는 MEMBER 테이블의 MEMBER_ID가 외래키로 포함이 될 것이다.

(2)와 같이 추가되는 member 객체는 이 MEMBER_ID 같은 외래키의 역할을 한다

 

- (3)에서 주문 정보를 저장한다

- (4)에서는 등록한 회원에 해당하는 주문 정보를 조회하고 있다

- (5)에서 findOrder.getMember()와 같이 주문에 해당하는 회원 정보를 가져와서 출력하고 있다

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

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

 

 

 

다대일 매핑에 일대다 매핑 추가

- 카페 주인 입장에서는 이 주문을 누가 했는지 주문한 회원의 회원 정보를 알아야 할 경우에는 다대일 매핑을 통해 주문한 사람의 정보를 조회할 수 있다

- 회원 입장에서는 내가 주문한 주문의 목록을 확인할 수 있어야 할 텐데 다대일 매핑만으로는 member 객체를 통해 내가 주문한 주문 정보인 order 객체들을 조회할 수 없다

이 경우, 다대일 매핑이 되어 있는 상태에서 일대다 매핑을 추가해 양방향 관계를 만들어주면 된다.

 

일대다에서 일(1)에 해당하는 Member 클래스

- 다대일 매핑에 일대다 매핑을 추가해서 양방향 관계를 만들어주었다

 

(1)의 @OneToMany(mappedBy = "member")

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

( mappedBy는 참조할 대상이 있어야 하는데 일대다 단방향 매핑의 경우 참조할 대상이 없기 때문이다 )

( 공식 API 문서에서는 @OneToMany 애너테이션의 mappedBy에 대해서 mappedBy의 값은 관계를 소유하고 있는 필드를 지정하는 것이라고 말하고 있다 )

- MEMBER 테이블과 ORDER 테이블의 관계에서 ORDER 테이블의 외래키로 MEMBER 테이블의 기본키 열인 MEMBER_ID의 값을 지정한다

- Order 클래스에서 외래키의 역할을 하는 필드는 member 필드 이다.

그렇기 때문에 (1)의 mappedBy의 값이 member가 되는 것이다

## 두 객체들 간에 외래키의 역할을 하는 필드는 무엇인가?

## 외래키의 역할을 하는 필드는 다(N)에 해당하는 클래스 안에 있다.

- 위 두가지를 기억하면서 mappedBy의 값을 지정해 주면 된다

 

 

 

다대일 매핑에 일대다 매핑을 추가하여 주문 정보 조회

 

(1)에서 member 객체에 order 객체를 추가해 준다

  - member 객체에 order 객체를 추가해주지 않아도 테이블에는 member 정보와 order 정보가 정상적으로 저장된다

  - 하지만 member 객체에 order 객체를 추가해주지 않으면 (5)에서 find() 메서드로 조회한 member 객체로 order를 그래        프  탐색하면 order 객체를 조회할 수 없다

      # 이유는 바로 find() 메서드가 1차 캐시에서 member 객체를 조회하는데 (1)에서 order를 추가해주지 않으면 1차 캐시에 저장된 member 객체는 order를 당연히 가지고 있지 않기때문이다

(2)에서 order 객체에  member 객체를 추가해 준다

  - order 객체에 member 객체를 추가해 주는 이유는 다대일 관계에서 보았듯이 member가 order의 외래키 역할을 하기 때문에 order 객체 저장 시, 필요하다

  - order 객체에 member 객체를 추가해주지 않으면 ORDERS 테이블에 저장된 주문 정보의 MEMBER_ID 필드가 null이 될 것이다

      # 외래키로 참조할 객체 정보(member)가 없기 때문이다

(3)에서 회원 정보를 저장하고, (4)에서 주문 정보를 저장한다

(5)에서 방금 저장한 회원 정보를 1차 캐시에서 조회한다

일대다 양방향 관계를 매핑했기 때문에 (6)과 같이 find() 메서드로 조회한 member로부터 객체 그래프 탐색을 통해 List 정보에 접근할 수 있다

 

 

다대다 연관 관계

- 실무에선 다대다의 관계를 가지는 테이블을 설계하는 경우가 많다

- 커피 주문 샘플 애플리케이션에서도 주문(Order)과 커피(Coffee)의 관계는 다대다 관계이다

 ( 하나의 주문에 여러 개의 커피가 속할 수 있고, 하나의 커피는 여러 주문에 속할 수 있기 떄문에 다대다 관계 이다 )

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

- 다대다 관계에 있는 ORDERS 테이블과 COFFEE 테이블 사이에 ORDER_COFFEE 테이블을 두고 두 개의 1대 다 관계로 만들었다

- ORDER_COFFEE 테이블은 ORDERS 테이블의 외래키와 COFFEE 테이블의 외래키를 가지고 있다

## 일대다 단방향 매핑은 외래키를 포함하지 않기 때문에 자주 사용되지 않는 매핑 방법이다. 그렇기에 두 개의 다대일 매핑이 필요하다, 그러고 나서 현실적으로 다대일 매핑을 통해 객체 그래프 탐색으로 원하는 객체를 조회할 수 없다면 그때 일대다 양방향 매핑을 추가하면 된다

 

 

일대일 연관관계

- 일대일 연관 관계 매핑은 다대일 단방향 연관 관계 매핑과 매핑 방법은 동일하다

- @ManyToOne 애너테이션이 아닌 @OneToOne 애너테이션을 사용한다

- 일대일 단방향 매핑에 양방향 매핑을 추가하는 방법도 다대일에 일대다 매핑을 추가하는 방식과 동일하다

- @ManyToOne 애너테이션이 아닌 @OneToOne 애너테이션을 사용한다

 

 

엔티티 간의 연관 관꼐 매핑 관장 방법

  • 일대다 매핑은 사용하지 않습니다.
  • 제일 먼저 다대일 단방향 매핑부터 적용합니다.
  • 다대일 단방향 매핑을 통해 객체 그래프 탐색으로 조회할 수 없는 정보가 있을 경우, 그때 비로소 양방향 매핑을 적용합니다.

----------------------------------------------------------------------------------------------------------------------------------------------------------------

 

 

  • Spring Data JDBC는 엔티티 간에 단방향 매핑만 지원하지만 JPA는 단방향과 양방향 매핑을 모두 지원한다.
  • JPA는 엔티티 간에 일대다, 다대일, 다대다, 일대일 연관 관계 매핑을 지원한다.
  • 일대다 관계는 외래키를 가지고 있어야 할 엔티티에 외래키 역할을 하는 객체 참조가 없기 때문에 가급적 사용하지 않는 것이 좋다.
  • 다대일 매핑(@ManyToOne)은 다대일에서 ‘다’에 해당하는 엔티티에서 사용한다.
    • @JoinColumn 애너테이션은 다대일 매핑(@ManyToOne)에 사용한다.
    • @JoinColumn 애너테이션의 name 애트리뷰트 값에는 테이블 조인 시 사용되는 외래키가 저장되는 열 이름을 지정한다.
  • 일대다(@OneToMany) 양방향 매핑은 다대일에서 ‘일’에 해당하는 엔티티에서 사용한다.
    • @OneToMany의 mappedBy 애트리뷰트의 값으로 외래키 역할을 하는 객체의 필드이름을 지정한다.
  • 다대다 연관 관계 매핑은 두 개의 다대일 단방향 매핑을 적용하고, 필요한 경우 양방향 매핑을 적용한다.
  • 일대일 연관 관계 매핑 방식은 @OneToOne 애너테이션을 사용한다는 것 외에 @ManyToOne 단방향 방식, 양방향 방식과 동일하다.

 

 

 

 

 

 

 

 

 

 

 

 

 

728x90