[JPA] 연관관계 매핑 기초
목표
-
객체와 테이블 연관관계의 차이를 이해하기
-
객체의 참조와 테이블의 외래 키를 매핑
연관 관계 매핑
- 방향 : 단방향, 양방향
- 다중성 : 다대일, 일대다, 일대일 ,다대다 이해
- 연관관계의 주인 : 객체 양방향 연관관계는 관리주인이 필요하다.
연관관계가 필요한 이유
- 객체하나 혹은 테이블 하나로 설계하고 개발할 수 없다.
- 회원과 팀이 있고 회원은 하나의 팀에만 소속될 수 있을때, 회원과 팀은 다대일 관계다.
- 이런 관계들을 표현하고 적용해서 개발해야한다.
객체를 테이블에 맞추어 모델링 하는것 ( 연관관계가 없는 객체 )
//팀 저장
Team team = new Team();
team.setName("TeamA");
em.persist(team);
//회원 저장
Member member = new Member();
member.setName("member1");
member.setTeamId(team.getId()); //객체지향과는 거리가있음
em.persist(member);
//조회를 할때에도 식별자로 다시 조회하고 그 값을 Team에서 다시 가져와서 확인해야함
//조회값
Member findMember = em.find(Member.class , member.getId());
// 연관관계가 없이 가져옴
Team findTeam = em.find(Team.class , team.getId());
객체지향 모델링 (연관관계 저장시)
//팀저장
Team team = new Team();
team.setName("TeamA");
em.persist(team);
//회원 저장
Member member = new Member();
member.setName("member1");
member.setTeam(team); // 단방향 연관관계 설정, 참조 저장
em.persist(member);
//조회
Member findMember = em.find(Member.class, member.getId());
//참조를 사용해서 연관관계 조회
Team findTeam = findMember.getTeam();
연관관계 저장하고 수정시
//새로운 팀B
Team teamB = new Team();
teamB.setName("TeamB");
em.persist(teamB);
//회원 1에 새로운 팀B 설정
member.setTeam(teamB);
단방향 연관관계
- 객체 지향 모델링 (객체 연관관계 사용)
- 관계가 어떤지랑 어떤 컬럼을 통해 조인하는지 명시해주면된다.
양방향 연관관계와 연관관계의 주인 - 중요 !
- 양방향 객체 연관관계를 매핑해도 테이블엔 변화 없음
- 테이블의 연관관계엔 외래키로 서로의 연관을 다 알수 있지만
- 객체에선 Team에서 Member로 갈수 없음
- 그래서 List members를 두어서 양방향으로 매핑이 가능하게 함.
객체의 양방향 관계
- 객체의 양방향 관계는 사실 양방향 관계가 아니라 서로 다른 단방향 관계 2개다.
- 객체를 양방향으로 참조하려면 단방향 연관관계를 2개 만들어야한다.
- A- > B (a.getB())
- B- > A (b.getA())
테이블의 양방향 관계
- 테이블은 외래 키 하나로 두 테이블의 연관관계를 관리한다. (양쪽으로 조인할 수 있다.)
연관관계의 주인 (Owner)
양방향 매핑 규칙 객체의 두 관계중 하나를 연관관계의 주인으로 지정해야함 연관관계의 주인만이 외래 키를 관리(등록, 수정) 주인이 아닌쪽은 읽기만 가능하다 주인은 mappedBy 속성 사용X 주인이 아니라면 mappedBy 속성으로 주인 지정
누구를 주인으로 해야할까? 외래키가 있는곳을 주인으로 정해라
양방향 매핑시 가장 많이 하는 실수
연관관계의 주인에 값을 입력하지 않음
코드
Member member = new Member();
member.setUsername("member1");
em.persist(member);
Team team = new Team();
team.setName("TeamA");
team.getMembers().add(member);
em.persist(team);
em.flush();
em.clear();
tx.commit();
- members는 읽기전용이므로 member.setTeam()을 통해서 team을 넣어야함 member에 !
Member member = new Member();
member.setUsername("member1");
Team team = new Team();
team.setName("TeamA");
em.persist(team);
member.setTeam(team);
em.persist(member);
em.flush();
em.clear();
tx.commit();
위 코드에서 team에 값을 넣어두고 추후 team의 mappedby된 것이 아닌 member(주인)을통해서 값을 넣어준다.
해결
양방향 매핑시 연관관계시 양쪽에 값 세팅은 모두 해주어야한다.
- 순수 객체 상태를 고려해서 항상 양쪽에 값을 설정해야한다.
- 연관관계 편의 메소드를 생성하자
- 양방향 매시핑에 무한 루프를 조심하자 ex) toString(), lombok, JSON 생성 라이브러리
- 실무에선 controller에서 엔티티로 반환 NO!
//연관관계 편의 메소드
//Member 클래스
public void setTeam(Team team){
this.team = team;
team.getMembers().add(this);
//this -> Member 인스턴스
}
양방향 매핑 정리
- 단방향 매핑만으로도 이미 연관관계 매핑은 완료
- 양방향 매핑은 반대 방향으로 조회(객체 그래프 탐색) 기능이 추가된 것 뿐
- JPQL에서 역방향으로 탐색할 일이 많음
- 단방향 매핑을 잘 하고 양방향은 필요할 때 추가해도 됨 (테이블에 영향을 주지않음)
😄 참고 : 인프런 김영한님의 JPA 기본 강의 및 교재
🌜 개인 공부 기록용 블로그입니다. 오류나 틀린 부분이 있을 경우
언제든지 댓글 혹은 메일로 지적해주시면 감사하겠습니다! 😄
개인메모