지난 포스팅에서는 단방향 연관관계에 알아보았다. 이어서, 조금 더 복잡한 개념인 양방향 연관관계에 대해 알아보자.
5.3 양방향 연관관계
양방향 연관관계는 양쪽 엔티티가 서로를 참조하는 관계를 의미한다. 예를 들어, 회원(Member)이 하나의 팀(Team)에 속해 있다고 가정할 때, 단방향 관계에서는 Member
가 Team
을 참조하는 구조였다. 이제 팀도 해당 팀에 속한 회원들을 참조하도록 설정하여 양방향 관계를 만들어 보자.
- 회원-팀: 다대일(N:1) 관계 / 회원 → 팀 (
Member.team
) - 팀-회원: 일대다(1:N) 관계 / 팀 → 회원 (
Team.members
)
@Entity
public class Member {
@Id
@Column(name = "MEMBER_ID")
private String id;
private String username;
@ManyToOne
@JoinColumn(name = "TEAM_ID")
private Team team;
public void setTeam(Team team) {
this.team = team;
}
// getters, setters 생략
}
@Entity
public class Team {
@Id
@Column(name = "TEAM_ID")
private String id;
private String name;
@OneToMany(mappedBy = "team")
private List<Member> members = new ArrayList<>();
// getters, setters 생략
}
- 회원(
Member
) 엔티티는 기존과 동일하게@ManyToOne
관계를 통해team
을 참조하고, 팀(Team
) 엔티티는 회원 컬렉션(members
)을 가지고 일대다 관계를 설정했다. - @OneToMany(mappedBy = "team"):
mappedBy
속성은 양방향 관계에서 반대쪽 매핑 필드를 지정한다. 즉,Member
엔티티의team
필드가 외래 키를 관리하므로,Team.members
는mappedBy
로 설정된다.
5.4 연관관계의 주인 (Owner)
양방향 연관관계에서는 외래 키를 실제로 관리하는 주체를 설정해야 한다. 연관관계의 주인은 데이터베이스에서 외래 키의 값을 변경할 수 있는 엔티티이며, 반대쪽은 읽기 전용으로 설정된다.
- 주인 엔티티가 외래 키를 관리하며, 이곳에서 외래 키를 변경하면 데이터베이스에 반영된다.
- 주인 엔티티는
mappedBy
속성을 사용하지 않는다. 반대로 주인이 아닌 엔티티는mappedBy
를 사용하여 주인을 지정한다.
주인 설정의 예
위 예제에서는 외래 키를 가진 Member.team
필드가 주인이 된다. Team.members
는 외래 키를 가지지 않으므로 주인이 아니며, mappedBy
를 통해 연관 필드(team
)를 지정하여 양방향 관계를 설정한다.
5.5 양방향 연관관계 저장
연관관계의 주인이 아닌 곳에 값을 입력해도 데이터베이스에는 반영되지 않는다. 예를 들어, Team.members.add(member)
를 호출해도 DB의 외래 키에는 영향을 주지 않는다. 반드시 주인 필드(Member.team
)에 값을 설정해야 한다.
public void testSave() {
Team team = new Team();
team.setId("team1");
team.setName("팀1");
em.persist(team);
Member member = new Member();
member.setId("member1");
member.setUsername("회원1");
member.setTeam(team); // 주인 필드에 값 설정
em.persist(member);
team.getMembers().add(member); // 연관 관계 추가 (주인에 반영되지 않음)
}
이 코드에서 연관관계의 주인인 member.setTeam(team);
만 데이터베이스에 영향을 준다.
5.6 양방향 연관관계의 주의점과 편의 메서드
양방향 관계에서는 객체의 참조를 양쪽에 모두 설정해야 탐색이 원활해진다. 만약 한쪽에만 값을 설정하면, 다른 방향에서 연관 객체에 접근할 수 없다. 따라서 연관관계 편의 메서드를 사용하는 것이 좋다.
연관관계 편의 메서드 예제
public class Member {
// 기존 코드 생략
public void setTeam(Team team) {
this.team = team;
team.getMembers().add(this); // 편의 메서드로 양쪽에 모두 값 설정
}
}
편의 메서드를 사용하면, 연관관계를 설정할 때 양쪽 엔티티의 필드에 동시에 값을 설정할 수 있다.
팀 변경 시 주의 사항
편의 메서드로 팀을 변경할 때는 기존 팀에서 해당 회원을 제거하는 로직을 추가해야 한다.
public void setTeam(Team team) {
if (this.team != null) {
this.team.getMembers().remove(this); // 기존 팀에서 제거
}
this.team = team;
team.getMembers().add(this); // 새로운 팀에 추가
}
이 코드를 통해, 회원의 팀을 변경할 때 기존 팀과의 연관관계도 제거하여 일관성을 유지할 수 있다.
정리
양방향 연관관계는 단방향에 비해 설정과 관리가 더 복잡하다. 연관관계의 주인을 설정하고, 주인 필드에서 외래 키를 관리해야 하며, 객체 간 참조를 양쪽에 모두 설정해야 한다.
양방향 매핑이 복잡하다면 먼저 단방향 매핑을 설정하고, 그 이후에 필요한 경우 양방향 관계를 추가하는 방법으로 접근하는 것이 좋다.
Reference
[도서]자바 ORM 표준 JPA 프로그래밍(김영한 저)
'DB > JPA' 카테고리의 다른 글
[📗자바 ORM 표준 JPA 프로그래밍] 다대일, 일대다, 일대일, 다대다 매핑 전략 (0) | 2024.11.20 |
---|---|
[📗자바 ORM 표준 JPA 프로그래밍] 단방향 연관관계 매핑하기 (0) | 2024.11.12 |
[📗자바 ORM 표준 JPA 프로그래밍] JPA의 기본 어노테이션과 테이블 매핑 (0) | 2024.11.11 |
[📗자바 ORM 표준 JPA 프로그래밍] 엔티티 매니저와 영속성 컨텍스트, 엔티티의 생명 주기 (0) | 2024.11.10 |
[📗자바 ORM 표준 JPA 프로그래밍] JPA 소개 및 기본 매핑하기 (0) | 2024.11.06 |
댓글