이번 포스팅에서는 양방향 매핑 시 주의해야할 점과 연관관계 편의 메서드 작성 방법에 대해 알아보겠습니다.
아래 이미지와 같이 Member와 Team 엔티티를 양방향 매핑했을 경우를 가정해 설명합니다.
들어가기 전에
위 연관관계에서 연관관계의 주인은 누구일까요?
바로 Member입니다. MEMBER 테이블에서 TEAM_ID라는 외래키를 갖고있기 때문이죠.
그렇다면 Member와 Team 엔티티에서 각각 team, members 변수는 어노테이션을 어떻게 선언해야할까요?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
|
@Entity
public class Member
{
...
@ManyToOne
@JoinColumn(name = "TEAM_ID")
private Team team;
}
@Entity
public class Team
{
...
@OneToMany
@Column(mappedBy = "team")
private List<Member> members = new ArrayList();
}
|
cs |
양방향 매핑 시 주의할 점
새 팀을 생성하고 새 멤버를 팀에 추가시킨다고 할 때, 아래 코드는 원하는 시나리오대로 동작할까요? 아니라면 어떤 부분에 문제가 있을까요?
1
2
3
4
5
6
7
8
9
10
11
12
|
// 1. 새 팀 생성
Team team = new Team();
team.setName("TeamA");
em.persist(team);
// 2. 새 멤버 생성
Member member = new Member();
member.setName("member1");
// 3. 팀에 멤버
team.getMembers().add(member);
em.persist(member);
|
cs |
코드 실행 시, 새 팀과 새 멤버는 생성이 되지만 멤버와 팀의 연관관계는 저장되지 않습니다.
연관관계의 주인은 Member인데, 이 연관관계를 Team에 지정해주었기 때문이죠.
그렇다면 코드를 수정해서, 연관관계의 주인인 Member에 연관관계를 지정해주면 모든 문제가 해결될까요?
아래 코드를 잘 봐주세요.
1
2
3
4
5
6
7
8
9
10
11
|
Team team = new Team();
team.setName("TeamA");
em.persist(team);
Member member = new Member();
member.setName("member1");
//연관관계의 주인에 값 설정
member.setTeam(team);
em.persist(member);
System.out.println(Arrays.toString(team.getMembers()));
|
cs |
이 코드가 실행되면 DB에는 새로운 멤버와 팀, 연관관계가 모두 정상적으로 저장됩니다.
하지만, 마지막 line에서 출력한 팀의 멤버 리스트에는 아무런 값이 존재하지 않게됩니다. team이라는 객체의 members 필드에 입력된 값이 없기 때문입니다. 만약, 마지막 line 수행 전 DB로부터 위 team의 데이터를 다시 받아오면 괜찮겠지만말이죠.
다시 이 코드에서 발생한 버그를 수정해보겠습니다.
1
2
3
4
5
6
7
8
9
10
11
12
13
|
Team team = new Team();
team.setName("TeamA");
em.persist(team);
Member member = new Member();
member.setName("member1");
member.setTeam(team); //**
em.persist(member);
// 팀에도 연관관계 멤버 세팅
team.getMembers().add(member);
System.out.println(Arrays.toString(team.getMembers()));
|
cs |
팀과 멤버를 저장하고, 팀 객체에도 연관관계에 해당하는 멤버 객체를 members 리스트에 추가해주었습니다.
그래서 마지막 line에서도 추가된 멤버의 정보가 출력되게 됩니다.
순수 객체 상태를 고려해, 양쪽 모두에 값을 세팅해야합니다.
이번엔 Member와 Team을 toString() 메서드를 사용했을때 어떤 일이 발생하는지 확인해보겠습니다.
1
2
3
4
5
6
7
8
9
10
11
12
|
Team team = new Team();
team.setName("TeamA");
em.persist(team);
Member member = new Member();
member.setName("member1");
member.setTeam(team); //**
em.persist(member);
team.getMembers().add(member);
System.out.println(team.toString());
|
cs |
위 코드처럼 team을 toString() 하게되면 team 객체의 필드들이 나열되고, 그 과정에서 members 리스트 필드를 마주하게됩니다. 그러면 members 리스트 요소인 Member 타입 객체를 찾게되고, Member 타입 객체의 필드를 나열하면서 team 필드를 만나게되고... 다시 Team 타입 객체를 찾게됩니다.
네 맞아요. 무한루프가 발생하게됩니다.
그래서 양방향 연관관계 매핑시에는 toString 메서드를 재정의해주셔야합니다.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
|
@Entity
public class Member
{
...
@Override
public String toString() {
return "Member{" +
"id=" + id +
", userName='" + userName + '\'' +
", age=" + age +
", roleType=" + roleType +
", localDate=" + localDate +
", localDateTime=" + localDateTime +
", description='" + description + '\'' +
", period=" + period +
", address=" + address +
", favoriteFoods=" + favoriteFoods +
", addressHistory=" + addressHistory +
", temp='" + temp + '\'' +
'}';
}
}
@Entity
public class Team
{
...
@Override
public String toString() {
return "Team{" +
"id=" + id +
", name='" + name + '\'' +
'}';
}
}
|
cs |
연관관계 편의 메서드 작성
앞서 살펴본 내용 중에서 연관관계에 있는 객체 양쪽에 값을 세팅해주어야한다는 내용이 있었습니다.
예제 코드에서는 간단해 문제가 없었지만, 동일한 로직이 여러곳에서 쓰이게되면 매번 같은 코드를 작성해주어야하죠.
그럴때 연관관계 편의 메서드를 작성하면 됩니다.
연관관계의 주인인 Member 엔티티에 아래 메서드를 추가합니다.
1
2
3
4
5
6
7
8
9
10
|
@Entity
public class Member
{
...
public void changeTeam(Team team)
{
this.team = team;
team.getMembers().add(this);
}
}
|
cs |
그리고 Member 객체를 생성하고 Team을 세팅해줄 때, team 필드의 setter인 setTeam() 대신 지금 작성한 연관관계 편의 메서드를 사용하는거죠.
1
2
3
4
5
6
7
8
9
|
Team team = new Team();
team.setName("TeamA");
em.persist(team);
Member member = new Member();
member.setName("member1");
// 연관관계 편의 메서드
member.changeTeam(team);
em.persist(member);
|
cs |
이 코드가 수행된 직후에 team에서 members 필드 값을 확인하게되면 member 객체가 추가되어있게 됩니다.
출처 :: 인프런 강의(자바 ORM 표준 JPA 프로그래밍 - 기본편)
'🌱 SPRING > JPA' 카테고리의 다른 글
[JPA] 상속관계 매핑 (0) | 2020.07.19 |
---|---|
[JPA] 다양한 연관관계 매핑 (0) | 2020.07.19 |
[JPA] 연관관계 매핑 기초 (0) | 2020.07.04 |
[JPA] 기본키 매핑 어노테이션 (0) | 2020.07.04 |
[JPA] 매핑 어노테이션 (0) | 2020.06.13 |