@ManyToOne
다중성을 나타내는, 다대일 관계를 매핑하는 어노테이션으로 작성 필수
@JoinColumn
name
속성은 매핑할 외래 키 이름을 지정한다.필드명(team)
+ _
+ 참조하는 테이블의 컬럼명(TEAM_ID)
team_TEAM_ID
로 테이블에 MEMBER
테이블에 컬럼이 생긴다.@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
}
}
public class Team {
@Id
@Column(name = "TEAM_ID")
private String id;
private String name;
...
}
테이블 연관 관계는 원래 외래 키를 사용해 양방향 조회가 가능하기 때문에 수정할 필요가 없다.
@OneToMany
mappedBy
속성은 양방향 관계일 때 사용하는데, 반대쪽 매핑의 필드 이름을 값으로 넘겨주면 된다.
Team
객체도Member
들에 대한 참조를 컬렉션을 활용해서 갖는다.
Member
- 수정 사항이 없다.@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;
}
}
Team
- 일대다 관계 매핑@Entity
public class Team {
@Id
@Column(name = "TEAM_ID")
private String id;
private String name;
@OneToMany(mappedBy = "team")
private List<Member> members = new ArrayList<Member>();
}
mappedBy
는 왜 필요하지?연관 관계의 주인을 지정하는 것은 외래 키 관리자를 지정하는 것이다.
JPA에서는 두 객체 연관 관계 중 하나를 정해서 테이블의 외래 키를 관리해야 한다.
즉, 두 연관 관계 중 하나를 주인으로 정해야 한다.
연관 관계의 주인만이 DB 연관 관계와 매핑되고, 외래키를 관리할 수 있다.
반면에, 주인이 아닌 쪽은 조회만 가능하다.
주인이 아니면, mappedBy
속성으로 주인을 지정해줘야 한다.
mappedBy
속성의 값으로 반대쪽 매핑의 필드 이름으로 주인으로 지정한다.
연관 관계의 주인은 테이블의 외래 키가 있는 곳으로 정해야 한다.
테이블 연관 관계에서 외래 키 TEAM_ID
는 MEMBER
테이블에 있다.
Member.team
을 주인으로 선택하면, 자기 테이블에 있는 외래 키를 관리한다.
하지만 Team.Members
를 주인으로 설정하면 떨어져서 외래 키를 관리해야 한다.
주의! 비즈니스적으로 더 중요한 역할을 하는 엔티티를 주인으로 설정하면 안된다!
연관 관계의 주인만이 외래 키의 값을 변경할 수 있다.
즉, 주인이 아닌 곳에서 데이터를 입력해도 변경 되지 않는다.
또한, 순수한 객체 관계까지 고려한다면, 양쪽에 모두 데이터를 입력해주는 것이 좋다.
public void test_bothSide(){
Team team1 = new Team("1", "팀1")
em.persist(team1);
// member1과 team1의 연관 관계 설정
Member member1 = new member("1", "회원1")
member1.setTeam(team1);
team1.getMembers().add(member1);
em.persist(member1)
// member2와 team1의 연관 관계 설정
Member member2 = new member("2", "회원2")
member2.setTeam(team1);
team1.getMembers().add(member2);
em.persist(member2)
}
양방향 연관 관계는 결국 양쪽 다 신경써야 한다.
실수로 둘 중 하나만 호출하는 일이 없게 두 코드를 하나인 것처럼 작성해두자!
1. 기존 팀 여부 확인 => 관계를 끊고, 반대편에서도 제거
2. 연관 관계의 반대편에도 추가하는 과정 확인
public void setTeam(Team team){
// 기존에 팀이 있었다면, 기존 관계를 끊고 새로운 팀을 추가해야 한다.
// 이렇게 하지 않으면, 연관 관계의 반대편에는 리스트에 기존 팀으로 기록된다.
if(this.team != null){
this.team.getMembers.remove(this);
}
// 연관 관계의 반대 쪽에도 추가해줌으로써 문제 발생을 최소화한다!
this.team = team;
team.getMembers().add(this);
}