양방향 연관관계를 이용할 때 가장 많이 하는 실수에 대해 알아보자.
이전 글에서 위와 같은 연관관계를 양방향 연관관계라고 하였고, 이 때 "외래키가 있는 곳을 주인으로 정해라" 라는 규칙에 따라 Member의 team을 연관관계의 주인으로 결정했다.
이 때 다음과 같은 코드를 작성한다고 가정해보자.
Member member = new Member();
member.setUsername("member1");
em.persist(member);
Team team = new Team();
team.setName("TeamA");
team.getMembers().add(member); // 주목 해야 할 부분
em.persist(team);
의도는 단순하다. member와 team 객체를 생성하고 그 생성한 member가 team에 소속되도록 하고싶어 작성한 코드이다. 이 코드를 실행한 후 DB에는 값이 적절하게 들어갈까? 확인해보자.
MEMBER 테이블에 추가한 데이터를 보니 TEAM_ID 값이 NULL이다. 나의 의도는 TeamA의 ID값인 2가 들어가길 원했는데 왜 안들어갔을까.... 추측해보자
Team의 members는 mappedBy 속성이 붙어 있는데 이는 이 변수가 양방향 연관관계의 주인이 아니라는 뜻이다. 즉, 읽기 전용(가짜 매핑)이므로 이 변수에 member를 아무리 넣어봤자 실제로 Member 테이블엔 아무런 영향을 끼칠 수 없다는 뜻이다.
그러므로 내가 의도한 대로 코드를 수정하면
// team.getMembers().add(member); 이 부분은 사실상 의미가 없는 코드
member.setTeam(team)
위처럼 수정 후 다시 프로그램을 실행해보면?
나의 의도대로 값이 잘 셋팅되있는것을 확인할 수 있다.
그렇다면 여기서 조금 더 생각해볼만한 문제가 있다. 개발할 때 마다 이렇게 연관관계 주인을 잘 찾아서 그 주인에 값을 할당하는것이 좋을까? 앞선 예제는 단순한 두개의 테이블로 예시를 들었지만 실제 우리의 비지니스 로직을 담당하는 수많은 테이블 간의 연관관계를 생각해보면 그리 쉬운 문제만은 아닐 것 같다.
이 문제를 해결할 간단한 방법이 있다...! 그것은 한마디로 말하자면
그냥 연관관계 주인 이런거 고려하지말고 양쪽에 다 넣어
라고 할 수 있겠다! JPA로만 따진다면 분명 연관관계 주인에만 값을 넣어주는것이 맞지만, 객체지향적인 측면에서는 양쪽에 값을 넣어주는것이 맞다.(추가로 연관관계의 주인에만 넣어줬을 때 문제가 발생할 여지가 있다.)
team.getMembers().add(member);
member.setTeam(team)
즉, 위처럼 그냥 양쪽에 다 넣어주는것이 헷갈릴 여지도 없을뿐더러 더 안전하다.
이를 조금 더 깔끔하게 처리하는 방법은 연관관계 편의 메소드를 만들어 사용하는것이다.
public void changeTeam(Team team) {
this.team = team;
team.getMembers().add(this);
}
위처럼 Member 클래스에 연관관계 편의 메소드를 작성하여 하나의 메소드 호출을 통해 양쪽에 값을 다 넣을 수 있도록 처리하는것이다. 이렇게 양방향 연관관계에서 흔히 하는 실수와 해결법에 대해 알아보았다. 마지막으로 이를 정리하면
양방향 매핑 정리