본문 바로가기
JPA

JPA 양방향 연관관계 일 때의 저장 및 연관관계 편의 메서드

by khds 2021. 12. 14.

연관관계를 일대다, 다대일로 데이터를 다루는 경우가 많다. 만약 한 엔티티에서만 일대다, 다대일을 설정하면 단방향 연관관계이고 두 엔티티 모두 다대일, 일대다 설정을 한다면 양방향 연관관계이다. 양방향 연관관계를 할 때 외래 키 설정이 제대로 안된 경우가 있을 수 있는데 아래의 간단한 예시 코드를 보며 살펴보자.

 

@Entity
class Member {
   
    ...

    @ManyToOne
    @JoinColumn(name="TEAM_ID")
    private Team team;
    
    ...
}

 

@Entity
class Team {
   
    ...

    @OneToMany(mappedBy = "team")
    private List<Member> members = new ArrayList<>();
    
    ...
}

 

 

위와 같이 Member 과 Team은 다대일 관계이며 양방향 연관관계이다.

 

여기서 아래와 같이 코드를 실행했다고 해보자.

 

public void testSave() {

   //팀1 저장
   Team team1 = new Teat("team1");
   
   //회원1 저장
   Member member1 = new Member("member1");
   member1.setTeam(team1);  // 연관관계설정 member1 -> team1
   
   em.persist(member1);
}

 

만약 위와 같이 설정했다면  Member 테이블에는 TEAM_ID가 제대로 설정이 됐을 것이다. 하지만 아래와 같은 코드로 실행하면 제대로 설정이 안 되어있고 null 이 들어가 있을 것이다.

 

public void testSave() {

   //회원1 저장
   Member member1 = new Member("member1");
   
   em.persist(member1);
   
   //팀1 저장
   Team team1 = new Teat("team1");
   team1.getMember().add(member1);
   
   em.persist(team1);
}

 

그 이유는 외래키를 가지고 있는 즉, 연관관계의 주인인 merber에다가 추가를 해야 연관관계가 나타나기 때문이다. 연관관계의 주인이 아닌 team에다 어떤 추가를 해도 무시가 되기 때문에 영향을 전혀 주지 않는다.

 

하지만 순수한 객체 상태에서는 양쪽 방향에 모두 값을 입력해주는 것이 가장 안전하다. 양쪽 방향 모두 값을 입력하지 않으면 JPA를 사용하지 않는 순수한 객체 상태에서 심각한 문제가 발생할 수 있다.

 

JPA에서는 member에 team을 설정하고 디비에 저장하면 연관관계가 설정이 되겠지만 객체만 따지자면 team에서는 member를 가졌다는 것이 안보이니까 team에서 member를 조회하면 아무것도 안 나올 것이다. 

 

그렇기에 웬만하면 객체를 고려하여 양쪽다 관계를 맺으면 된다.

 

여기서 양쪽다 관계를 맺기 편하게 하기 위해 연관관계 편의 메서드라는 것이 있다. 

아래의 코드를 보자.

 

public class Member {

    private Team team;
    
    public void setTeam() {
        this.team = team;
        teatm.getMember().add(this);
    }
    
    ...    
}

 

이렇게 설정한다면 member에서 setTeam을 호출하는 것만으로도 team에다 member를 추가할 수 있다.

 

하지만 여기서 한 가지 문제가 있다. 만약 member에서 team1을 지우지 않은 상태에서 team2로 변경한다면 team1은 여전히 member를 가지고 있지만 member는 team2와 서로 관계를 가지고 있다. 그렇기에 setTeam 메서드를 아래와 같이 작성해 주는 것이 좋다.

 

public void setTeam() {

	//기존 팀과 관계를 제거
    if (this.team !=null) {
    	this.team.getMember().remove(this);
    }
    this.team = team;
    team.getMember().add(this);
}

 

이렇게 되면 team을 변경해도 문제가 발생하지 않을 것이다.

 

 

참고

 

자바 ORM 표준 JPA 프로그래밍 - 김영한