교재: 자바 ORM 표준 JPA 프로그래밍
5장의 목표는 객체의 참조와 테이블의 외래 키를 매핑하는 것이다.
5장의 핵심 키워드:
ex: 회원과 팀의 관계를 알아보자
- 회원과 팀이 잇다
- 회원은 하나의 팀에만 소속될 수 있다
- 회원과 팀은 다대일 관계다
객체 연관관계
테이블 연관관계
-- 회원과 팀을 조인하는 SQL
SELECT *
FROM MEMBER M
JOIN TEAM T ON M.TEAM_ID = T.ID
-- 팀과 회원을 조인하는 SQL
SELECT *
FROM TEAM T
JOIN MEMBER M ON T.ID = M.TEAM_ID
member1.setTeam(team1);
member2.setTeam(team1);
Team findTeam = member1.getTeam();
데이터베이스는 외래 키를 사용해서 연관관계를 탐색하는 것이 조인이라 한다.
SELECT T.*
FROM MEMBER M
JOIN TEAM T ON M.TEAM_ID = T.ID
WHERE M.MEMBER_ID = 'member1'
ex: 회원 엔티티 매핑
@ManyToOne
@JoinColumn(name="TEAM_ID")
private Team team;
속성:
속성:
public void testSave() {
//팀1 저장
Team team1 = new Team("team1", "팀1");
em.persist(team1);
//회원1 저장
Member member1 = new Member("member1", "회원1");
member1.setTeam(team1); // 연관관계 설정: member1 -> team1
em.persist(member1);
//회원2 저장
Member member2 = new Member("member2", "회원2");
member2.setTeam(team1); // 연관관계 설정: member2 -> team1
em.persist(member2);
}
객체 그래프 탐색
Team team = member.getTeam();
객체지향 쿼리 사용 JPQL
List<Member> resultList = em.createQuery(jpql, Member.class)
.setParameter("teamName", "팀1");
.getResultList();
//회원1에 새로운 팀2 설정
Member member = em.find(Member.class, "member1");
member.setTeam(team2);
member1.setTeam(null); //연관관계 제거
member1.setTeam(null); //회원1 연관관계 제거
member2.setTeam(null); //회원2 연관관계 제거
em.remove(team); //팀 삭제
회원 → 팀 접근하고 반대 방향 팀 → 회원 접근할 수 있는 양방향 연관관계로 매핑해 볼 것이다.
매핑한 팀 엔티티:
@Entity
public class Team {
@Id
@Column(name="TEAM_ID")
private Stirng id;
// 추가
@OneToMany(mappedBy = "team")
private List<Member> members = new ArrayList<Member>();
}
mappedBy: 양방향 매핑일 때 사용, 반대 쪽 매핑의 필드 이름을 값으로 주면된다.List<Member> members = team.getMembers(); // (팀 -> 회원), 객체 그래프 탐색
복습:
→ 엔티티를 양방향 관계로 설정하면 객체의 참조는 둘인데 외래 키는 하나다.
연관관계의 주인
연관관계의 주인은 외래 키가 있는 곳
연관관계의 주인은 외래 키(FK)를 가진 쪽이고 Team–Member 관계에서는 TEAM_ID를 가진 MEMBER가 주인이 된다.
양방향 연관관계는 연관관계의 주인이 외래 키를 관리한다. 주인이 아닌 방향은 값을 설정하지 않아도 데이터베이스에 외래 키 값이 정상 입력된다.
team1.getMembers().add(member1); // 무시
team1.getMembers().add(member2); // 무시
member1.setTeam(team1); // 연관관계 설정
member2.setTeam(team1); // 연관관계 설정
외래 키 값이 저장되지 않는다면 연관관계의 주인이 아닌 쪽에서 값을 설정했는지 먼저 확인해야 한다.
객체 관점에서 양쪽 방향에 모두 값을 입력해주는 것이 가장 안전하다.
member1.setTeam(team1); // 회원 -> 팀
team1.getMembers().add(member1); // 팀 -> 회원
양방향 연관관계는 양쪽 다 신경 써야 한다. 각각 호출하다 보면 실수로 둘 중 하나만 호출해서 양방향이 깨질 수 있다. 편의 메소드 사용 방법:
private Team team;
public void setTeam(Team team) {
if (this.team != null) {
this.team.getMembers().remove(this);
}
this.team = team;
team.getMembers().add(this);
}
}