[JPA]스프링 연관관계 매핑
단방향 연관관계
- 회원과 팀이있다.
- 회원은 하나의 팀에만 소속될수 있다.
- 회원과 팀은 다대일 관계
객체중심으로 볼때
객체 연관관계
회원객체와 팀 객체는 단방향 관계 , 회원은 Member.team 필드를 통해서 팀을 알수있지만 반대로 팀은 회원을 알수 없음.
member -> team의 조회는 member.getTeam()으로 가능, 반대 방향인 team ->member는 접근 할수가없음
테이블 중심으로 볼때
회원 테이블과 팀 테이블은 양방향 관계, TEAM_ID로 외래키를 통해 회원가 툄을 조인, 반대로 팀과 회원도 조인 가능
객체를 테이블에 맞춰서 모델링을 하게되면
• 테이블은 외래 키로 조인을 사용해서 연관된 테이블을 찾는다.
• 객체는 참조를 사용해서 연관된 객체를 찾는다.
• 테이블과 객체 사이에는 이런 큰 간격이 있다
@Entity
public class Member {
@Id @GeneratedValue
private Long id;
@Column(name = "USERNAME")
private String name;
@Column(name = "TEAM_ID")
private Long teamId;
…
}
@Entity
public class Team {
@Id @GeneratedValue
private Long id;
private String name;
…
}
//조회
Member findMember = em.find(Member.class, member.getId());
//연관관계가 없음
Team findTeam = em.find(Team.class, team.getId());
식별자로 다시 조회하게됨 ,객체지향적이지 않음
객체 지향 모델링 (객체의 참조와 테이블의 외래키를 매핑)
@Entity
public class Member {
@Id @GeneratedValue
private Long id;
@Column(name = "USERNAME")
private String name;
private int age;
// @Column(name = "TEAM_ID")
// private Long teamId;
@ManyToOne
@JoinColumn(name = "TEAM_ID")
private Team team;
ORM 매핑
//조회
Member findMember = em.find(Member.class, member.getId());
//참조를 사용해서 연관관계 조회
Team findTeam = findMember.getTeam();
참조로 연관관계를 조회 - 객체 그래프 탐색
객체 연관관계와 테이블 연관과계의 가장 큰차이
객체간에 연관관계를 양방향으로 만들고 싶으면 반대쪽에도 필드를 추가해서 참조해야함, 결국 연관관계를 하나 더 만들어야함 , 객체에선 서로 서로 참조하는것을 양방향 관계 ,따지고 보면 양방향 관계가 아니라 서로다른 단방향 관계가 2개인 것임 , 테이블은 외래키 하나로 양방향으로 조인가능
객체 연관관계 vs 테이블 연관관계
- 객체는 참조로 연관관계를 맺음
- 테이블은 외래키로 연관관계를 맺음
참조를 사용하는 객체의 연관관계는 단방향
- A → B (a.b)
객체를 양방향으로 참조하려면 단방향 연관관계 2개를 만듦
- A → B (a.b)
- B → A (b.a)
외래키를 사용하는 테이블의 연관관계는 양방향
- A JOIN B 가 가능하면 반대로 B JOIN A도 가능
양방향 연관관계, 연관관계 주인
양방향 매핑
@Entity
public class Member {
@Id @GeneratedValue
private Long id;
@Column(name = "USERNAME")
private String name;
private int age;
@ManyToOne
@JoinColumn(name = "TEAM_ID")
private Team team;
}
@Entity
public class Team {
@Id @GeneratedValue
private Long id;
private String name;
@OneToMany(mappedBy = "team")
List<Member> members = new ArrayList<Member>();
…
}
객체는 양방향 관계라는것이 없음, 서로다른 단방향 연관관계 2개를 양방향인것처럼 보이게 할뿐
객체 연관관계
회원 → 팀 연관관계 1개(단방향)
팀 → 회원 연관관계 1개(단방향)
class A {
B b;
}
class B {
A a;
}
테이블 연관관계
회원 ↔ 팀 연관관계 1개(양방향)
MEMBER.TEAM_ID 외래키 하나로 양방향 연관관계를 가짐 (양쪽으로 조인 가능)
SELECT *
FROM MEMBER M
JOIN TEAM T ON M.TEAM_ID = T.TEAM_ID
SELECT *
FROM TEAM T
JOIN MEMBER M ON T.TEAM_ID = M.TEAM_ID
테이블은 외래키 하나로 두 테이블의 연관관계를 관리 , 엔티티를 단방향으로 매핑하면 참조를 하나만 사용하므로 이참조로 외래키를 관리하면됨, 그러나 양방향으로 매핑하면
회원 -> 팀, 팀-> 회원 두곳에서 서로를 참조, 따라서 객체의 연관관계를 관리하는 포인트는 2곳으로 늘어남.
엔티티를 양방향 연관관계로 설정하면 객체의 참조는 둘인데 외래키는 하나임, 따라서 둘차이가 발생하기때문에 외래키를 관리 해야함
이런차이로 인해 JPA는 두객체 연관관계 중 하나를 정해서 테이블의 외래키를 관리해야함 이것을 연관관계의 주인(Owner)이라 함
연관관계의 주인만이 데이터베이스 연관관계와 매핑되고 외래 키를 관리(등록,수정,삭제) 할수 있음, 반면에 주인인 아닌 쪽은 읽기만 가능
- 주인은 mappedBy 속성을 사용x
- 주인이 아닌쪽은 amppedBy 속성을 사용해서 속성의 값으로 연관관계의 주인을 지정
외래 키가 있는 있는 곳을 주인으로 정해라
여기서는 Member.team이 연관관계의 주인
양방향 매핑시 연관관계의 주인에 값을 입력
Team team = new Team();
team.setName("TeamA");
em.persist(team);
Member member = new Member();
member.setName("member1");
team.getMembers().add(member);
//연관관계의 주인에 값 설정
member.setTeam(team); //**
em.persist(member);
단방향 매핑만으로도 이미 연관관계 매핑은 완료
• 양방향 매핑은 반대 방향으로 조회(객체 그래프 탐색) 기능이 추
가된 것 뿐
• JPQL에서 역방향으로 탐색할 일이 많음
• 단방향 매핑을 잘 하고 양방향은 필요할 때 추가해도 됨
(테이블에 영향을 주지 않음)