본문 바로가기
[IT]/JPA

[JPA] 양방향 연관관계에서의 주의할 점( N:1 )

by dop 2021. 3. 19.

 JPA의 연관관계 문제점

JPA의 영속성 컨텍스트는 데이터베이스를 객체 관점으로 관리하기 위해 만들어졌지만,
태생적인 차이로 문제점이 생기곤 하는데, 이번에는 연관관계 설정시 주의할 점을 알아보자

[데이터베이스 관점]

team의 id를 fk로 활용하여 양방향 매핑이 가능하다

[객체 관점]

양쪽의 객체에 연관관계 대상에 대한 정보를 넣어줘야 한다

JPA를 사용하게되면 객체와 DB의 연관관계 방식의 불일치로 문제점이 생기게 된다.

// ----------테스트 코드 ------------//

Team team1 = new Team();
Team team2 = new Team();

team1.setName("team1");
team2.setName("team2");

teamRepository.save(team1);
teamRepository.save(team2);

Member member1 = new Member();
Member member2 = new Member();

member1.setName("AAA");
member1.setTeam(team1);
member2.setName("BBB");
member2.setTeam(team2);

memberRepository.save(member1);
memberRepository.save(member2);

 

위와같은 코드가 실행되었을 때, team1에는 member1이 team2에는 member2가 존재하는 상황이다.

그런데 이때, member1이 team2로 이적했다고 가정해보자.

//----------------테스트 코드----------//
member1.setTeam(team2); //member1의 team을 변경
team2.getMembers().add(member1); // team2에 member1추가
// 변경감지로 영속성 컨텍스트에 해당내용 적용됨

// 이렇게만 하면 끝일까????

 분명 영속성 컨텍스트는 변경된 내용을 적용하게 된다. DB에도 원하는대로 해당 컬럼이 변경된다.

하지만 JPA의 영속성 컨텍스트와 DB는 동일한 방식으로 구성된게 아니고 객체의 특성상 문제가 발생하게 된다.

 

위 코드에서는 객체 team1에는 아무런 작업을 해주지 않는다. 즉, DB는 옳게 적용 되었다고 하더라도 영속성 컨텍스트의 team1에는 아직 member1이 존재하는 상태가 된다.

 

이 문제를 해결하기위해 둘중 주인 객체가 되는 Member의 SetTeam메소드를 다음과 같이 변경해주어야 한다.

// MemberRepository 클래스

public void setTeam(Team team){
	if(this.team != null){ // 현재 멤버가 원래 팀이 있었다면 그 팀에서 삭제
    	this.team.getMembers().remove(this);
    }
	this.team = team;// 현재멤버의 팀 설정
    this.team.getMembers().add(this); // 해당팀에도 멤버로 추가 
}

setTeam의 메소드 자체에 멤버객체의 팀 설정, 팀 객체에 멤버추가, 이전 팀에서 삭제하는 로직을 모두 작성해줌으로써

//----------------테스트 코드----------//
member1.setTeam(team2); //member1의 team을 변경

앞서 작성한 팀 변경코드는 이렇게 변경된다.

 

 

728x90