[TIL] 23.01.11 JPA ,연관관계

hyewon jeong·2023년 1월 11일
0

Spring

목록 보기
20/59

이번 블로그 만들기 프로젝트에서 연관관계의 중요성을 알게 되어
복습 겸 추후 보기 위해 글을 남긴다.

블로그
User와 Post 의 관계를 보면 User 1명이 여러개의 post를 가질 수 있다.

@ManyToOne 단방향

TABLE_POSTS 테이블에 존재하는 user_id 컬럼을 통해 POSTS Entity에 있는 user 필드의 정보를 채운다.

여러개의 게시글을 사용자 한명에게 사용될수 있으므로 @ManyToOne 어노테이션을 추가한다.

연관관계의 주인임을 나타내고 물리 테이블에 있는 user_id 컬럼을 통해 user 필드를 채우기 위해 @JoinColumn을 작성한다.

TABLE_POSTS를 조회할때 user_id(PK)를 Join key로 사용해서 TABLE_USER에 있는 사용자 정보를 함께 불러온다.

ManyToOne 양방향

Posts Entity의 user필드가 관계의 주인이고, User Entity에서 정보를 조회할 수 있도록 양방향 매핑을 한다.

추가적으로 양방향 매핑을 위해 User Entity에 코드 추가

  • User Entity는 다수의 posts entity를 가질 수 있으므로 List형으로 객체를 정의한다.

  • @OneToMany 추가 :사용자 한명이 여러개의 게시글을 가질 수 있다.

  • 조회하려는 정보는 Posts Entity의 user 정보를 참고할것이기 때문에 mappedBy를 통해 연관관계를 매핑한다. ( 생략하면 실행시 중간 테이블 생성됨!! )

  • 게시글 추가의 편의를 위한 addPosts메소드를 추가한다
    ( 이때 주의할 점은 게시글을 추가한 뒤 게시글에 대한 유저정보를 저장해줘야 물리테이블에 user값이 저장되어 에러가 발생하지 않는다.

public void addPosts(Posts posts){
  this.postList.add(posts);
  posts.setUser(this);
  }

OneToMany 단방향

@ManyToOne에는 mappedBy 옵션이 없기 때문에 @OneToMany가 관계의 주인일 경우 양방향 매핑이 불가능하다. ( = @ManyToOne은 항상 주인이 된다. )

이렇게 연관관계 매핑이 된다면 User Entity의 accounts 필드의 정보를 변경하게 된다면 ( 사용자가 보유한 계좌정보가 변경될때 ) TABLE_USER의 쿼리문이 아닌 TABLE_ACCOUNT에 대한 쿼리문이 나가게된다. 가능하면 User Entity의 내용이 수정되었을땐 TABLE_USER가 중심이 되는 쿼리가 나가는게 좀더 명확하고 이해하기에도 쉽다. 따라서 가능하면 연관관계의 주인은 @ManyToOne이 되도록하자.

참고 https://soojong.tistory.com/entry/JPA-ManyToOne-OneToMany-%EC%9D%B4%ED%95%B4%ED%95%98%EA%B8%B0

연관관계 옵션

JPA orphanRemoval

@OneToMany(cascade = {CascadeType.ALL}, fetch = FetchType.EAGER, orphanRemoval = true)

보통 1:N 관계 테이블 설정할때 저렇게 옵션을 추가해준다.

👼🏻자식 엔티티의 변경이 있다면

📌JPA 에서 자식엔티티의 수정은 insert -> update (set null)-> delete(orphanRemoval =true를 통해 고아객체가 삭제됨) 순으로 이어지는데

변경된 자식을 먼저 insert 하고

기존의 자식을 NULL로 update 한다.

그리고 orphanRemoval 옵션을 true 로 하면 기존 NULL처리된 자식을 DELETE 한다.

PK(JoinColumn)값이 NULL로 변한 자식은 고아객체라고 하여 연결된 점이 없는 객체이다.

orphanRemoval옵션은 바로 이 고아객체를 삭제해주는 역활을 한다.

CascadeType.REMOVE와 orphanRemoval = true 차이

비교 결과
부모 엔티티 삭제

CascadeType.REMOVE와 orphanRemoval = true는 부모 엔티티를 삭제하면 자식 엔티티도 삭제한다.
부모 엔티티에서 자식 엔티티 제거

CascadeType.REMOVE는 자식 엔티티가 그대로 남아있는 반면, orphanRemoval = true는 자식 엔티티를 제거한다.

주의점
두 케이스 모두 자식 엔티티에 딱 하나의 부모 엔티티가 연관되어 있는 경우에만 사용해야 한다.

예를 들어 Member(자식)을 Team(부모)도 알고 Parent(부모)도 알고 있다면, CascadeType.REMOVE 또는 orphanRemoval = true를 조심할 필요가 있다. 자식 엔티티를 삭제할 상황이 아닌데도 어느 한쪽의 부모 엔티티를 삭제했거나 부모 엔티티로부터 제거됐다고 자식이 삭제되는 불상사가 일어날 수 있기 때문이다.

그러므로 @OneToMany에서 활용할 때 주의를 기울이고, @ManyToMany에서는 활용을 지양하자.

profile
개발자꿈나무

0개의 댓글