이번 블로그 만들기 프로젝트에서 연관관계의 중요성을 알게 되어
복습 겸 추후 보기 위해 글을 남긴다.
블로그
User와 Post 의 관계를 보면 User 1명이 여러개의 post를 가질 수 있다.
위의 블로그를 요약하자면 우선순위
1. 연관관계 맺을시 단방향으로 매핑시키고 추후 필요시 양방향으로 매핑시킨다.
2. 일대다의 단방향, 양방향 지양 -> 다대일 양방향 지향
3. 다대다 지양 -> 일대다 , 다대일 로 지향
TABLE_POSTS 테이블에 존재하는 user_id 컬럼을 통해 POSTS Entity에 있는 user 필드의 정보를 채운다.
여러개의 게시글을 사용자 한명에게 사용될수 있으므로 @ManyToOne 어노테이션을 추가한다.
연관관계의 주인임을 나타내고 물리 테이블에 있는 user_id 컬럼을 통해 user 필드를 채우기 위해 @JoinColumn을 작성한다.
TABLE_POSTS를 조회할때 user_id(PK)를 Join key로 사용해서 TABLE_USER에 있는 사용자 정보를 함께 불러온다.
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);
}
@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
@OneToOne, @OneToMany만 사용 가능
@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는 자식 엔티티를 제거한다.
주의점
두 케이스 모두 자식 엔티티에 딱 하나의 부모 엔티티가 연관되어 있는 경우에만 사용해야 한다.
예를 들어 Member(자식)을 Team(부모)도 알고 Parent(부모)도 알고 있다면, CascadeType.REMOVE 또는 orphanRemoval = true를 조심할 필요가 있다. 자식 엔티티를 삭제할 상황이 아닌데도 어느 한쪽의 부모 엔티티를 삭제했거나 부모 엔티티로부터 제거됐다고 자식이 삭제되는 불상사가 일어날 수 있기 때문이다.
그러므로 @OneToMany에서 활용할 때 주의를 기울이고, @ManyToMany에서는 활용을 지양하자.