자바/JPA

양방향 매핑관계 - 주의, 정리

망재이 2023. 8. 16. 15:02

★  양방향 매핑시 가장 많이 하는 실수

  • 연관관계 주인에는 값을 입력하지 않고, 주인이 아닌 곳에만 값을 입력하는 것

- member.team에는 값을 입력하지 않고 team.member에만 값을 입력하면 TEAM_ID에는 null이 들어간다

-> JPA는 연관관계 주인이 아니면 신경을 안쓰기 때문!

- member.team에 값을 저장하면 TEAM_ID에 1이 들어간 것을 확인할 수 있다.

- 양방향은 연관관계의 주인에만 값을 저장해도 데이터베이스에 값이 저장되는건 전혀 문제가 없지만, 순수한 객체 관계를 고려해서 team.members에도 값을 저장해주는게 좋다.

 

  • 양방향 매핑에서 연관관계의 주인에만 값을 저장할 경우

- member.team에만 값을 입력하고 List 컬렉션을 이용해서 members의 정보를 불러오려고 할 때, 문제가 생길 수 있는 경우이다.

- flush와 clear를 통해서 영속성 컨텍스트를 비워주지 않는다면, Team이 그대로 영속성 컨텍스트에 들어가있는 상태로 컬렉션에 아무런 값이 없는 상태로 저장되어 있기 때문에 조회가 되지 않는다. (순수한 객체 상태)

- flush와 clear를 해줬을 경우 영속성 컨텍스트의 1차 캐시가 비워져 있으므로 select문을 통해서 List 컬렉션을 조회할 수 있다.

- 이런 경우를 대비하기 위해서 양방향 전부 값을 넣어주는 것이 좋다!

 

  • 연관관계 편의 메소드 생성

- 양방향 연관관계는 member.setTeam(team)과 team.getMembers().add(member) 둘 다를 신경써야 하므로 각각 호출하다 보면 실수로 하나만 호출할 가능성이 높다. 이를 방지하기 위해서 member.team에 값을 저장할 때 team.members에도 값이 저장되도록 메소드를 설정해주는 것이 편리하다.

set, get 메소드 이름을 사용하는 것보다는 changeTeam 등 메소드 이름을 직접 설정해주는 게 좋음

- 편의 메소드를 만들어준 후, 같은 코드를 실행해주면 List 컬렉션이 조회되는 것을 확인할 수 있다.

 

⭐︎ 편의 메소드를 생성할 때 조금 더 신경써줘야 할 부분

  • team을 변경할 경우 기존에 있던 team -> member 관계 제거
    - 이 부분은 실제 개발을 진행할 때 서비스 로직에 따라 좀 더 신경써줘야 하는 부분인데, 어떻게 편의 메소드를 사용할지에 따라 맞게 수정하면 된다.
    - 양방향 관계의 경우 member <-> teamA 이렇게 설정되어 있던 관계를 member <-> teamB로 변경할 때 member <- teamA 관계를 지워주지 않으면 오류가 생길 수 있다.

 

  • team.addMember()가 필요할 경우
    - 필요에 따라 팀에서 회원을 추가해야할 경우가 있는 경우 연관관계 주인은 그대로 두되, 편의 메소드만 설정해주면 된다.
    - 다만, 멤버에서 팀을 추가할지 팀에서 멤버를 추가할지 한 가지 경우만 정해서 사용하는 것이 좋다.

 

  • 양방향 매핑시 무한 루프를 주의
    - Member, Team 객체 각각 toString() 메소드를 생성하면 members를 불러올 때 List 안에 있는 모든 member에 toString()을 생성하면서 무한 루프에 걸려버릴 수 있음
    - 롬복 역시 마찬가지이므로, 롬복에서 toString을 쓰는건 지양하는 것이 좋고, JSON의 경우에는 컨트롤러에서 절대 엔티티를 리턴하지 말 것!!

    그 이유는
    1. 무한루프
    2. 엔티티를 변경하는 순간 굉장해 복잡해지기 때문이다. 실무에서 사용할 때는 엔티티를 그대로 리턴하는 것이 아니라 DTO로 변환해서 컨트롤러에서 리턴하도록 짜는 것이 좋다.

 

 

★ 정리

- 단방향 매핑만으로 테이블과 객체의 연관관계 매핑은 이미 완료되었다. (이미 객체 입장에서는 단방향 매핑만으로 끝난 것)

- 단방향 매핑으로 설정해놓고, 개발하면서 역방향으로 JPQL을 짜서 탐색할 일이 많을 경우 필요에 의해서 양방향 매핑으로 설정해도 충분하다 (단방향 매핑만 잘 설정해놓으면, 양방향 매핑 설정은 간단하다. 테이블에 영향을 주지 않기 때문이다.)

- 반대 방향으로 저장해야할 일이 있다면 주인은 건드리지 말고 addMember()메소드처럼 편의 메소드만 잘 활용하면 된다.

- 양방향 연관관계를 매핑하려면 객체에서 양쪽 방향을 모두 관리해야 한다.

- 비즈니스 로직을 기준으로 연관관계 주인을 정하는 것이 아니라 외래 키의 위치로 정하는 것이 좋다.

728x90