양방향 연관관계와 연관관계의 주인
@Entity
public class Member {
@Id @GeneratedValue
@Column(name = "MEMBER_ID")
private Long id;
@Column(name = "USERNAME")
private String username;
//Member와 Team은 다 대 1 관계
@ManyToOne
@JoinColumn(name = "TEAM_ID")
private Team team;
}
@Entity
public class Team {
@Id @GeneratedValue
@Column(name = "TEAM_ID")
private Long id;
private String name;
//회원에서 팀을 참조할 뿐만 아니라
//팀에서도 회원을 참조할 수 있도록 팀에 멤버 리스트를 추가(양방향 매핑)
@OneToMany(mappedBy = "team") //팀과 멤버는 1 대 다 관계이고, team은 Member의 team 변수로 매핑되어 있음을 설정
private List<Member> members = new ArrayList<>();
}
//양방향 매핑 후 반대 방향으로 객체 그래프 탐색
Team findTeam = em.find(Team.class, team.getId());
int memberSize = findTeam.getMembers().size(); //역방향 조회
- 객체와 테이블 간의 연관관계를 맺는 차이
- 객체의 양방향 관계는 단방향 2개를 합친 것이다.
- 회원 → 팀 연관관계
- 팀 → 회원 연관관계
- 테이블의 양방향 관계는 FK 하나를 지정하면 어느 쪽으로든 관계가 형성된다.(양쪽으로 조인)
- 회원 ↔ 팀의 연관관계
- 객체의 양방향 관계는 단방향 2개를 합친 것이다.
- 연관관계 주인 지정하기
- 양방향 매핑을 하려면 객체의 두 관계 중 하나를 연관관계의 주인으로 지정한다.
- 주인이 아닌 쪽에 mappedBy 속성을 지정하기만 하면 된다.
- 연관관계의 주인만이 외래 키를 등록, 수정할 수 있다.
- 주인이 아닌 쪽은 읽기만 가능하다.
- 비즈니스 로직을 기준으로 연관관계의 주인을 선택하면 안 된다.
- 외래 키가 있는 곳을 주인으로 지정한다.
양방향 매핑시 주의점
//양방향 매핑시 많이 하는 실수
//연관관계의 주인에 값을 입력하지 않음
Team team = new Team();
team.setName("TeamA");
em.persist(team);
Member member = new Member();
member.setUsername("member1");
//역방향(주인이 아닌 방향)만 연관관계 설정하면 fk에 null이 들어간다.
team.getMembers().add(member);
em.persist(member);
team.getMembers().add(member);
member.setTeam(team); //연관관계의 주인에 값 설정
em.persist(member);
- 양방향 매핑 시 연관관계의 주인에 값을 입력해야 한다.
- 순수한 객체 관계를 고려해서 항상 양쪽에 값을 설정하자.
- 코드를 간결히 하고 싶으면 연관관계 편의 메소드를 생성하자.
- 연관관계 편의 메소드는 한 쪽만 사용해야 한다.
- Member의 연관관계 편의 메소드를 이용한 경우
@Entity
public class Member {
...
//연관관계 편의 메소드
public void changeTeam(Team team){
this.team = team;
team.getMembers().add(this);
}
}
member.changeTeam(team);
em.persist(member);
- Team의 연관관계 편의 메소드를 이용한 경우
@Entity
public class Team {
...
//연관관계 편의 메소드
public void addMember(Member member){
member.setTeam(this);
members.add(member);
}
}
team.addMember(member);
em.persist(member);
- 양방향 매핑 시 무한 루프를 조심하자.
- toString(), lombok, JSON 생성 라이브러리
- lombok으로 toString()를 이용하지 말자.
- Controller에는 Entity를 JSON으로 반환하지 말자.
- 무한 루프 문제
- Entity가 변경될 수도 있으며, 문제가 생길 수 있다.
- DTO로 변환해서 반환하자.
양방향 매핑 정리
- 단방향 매핑만으로 이미 연관관계 매핑이 완료된 것이다.
- 양방향 매핑은 반대 방향으로 조회(객체 그래프 탐색) 기능이 추가된 것 뿐
- JPQL에서 역방향으로 탐색할 일이 많다.
- 단방향 매핑을 잘 해두면 양방향은 필요할 때 추가하면 된다.
- 테이블에 영향을 주지 않기 때문