4

yeoro·2021년 9월 17일
0

연관관계 매핑 기초

단방향 연관관계

목표

  • 객체와 테이블 연관관계의 차이 이해
  • 객체의 참조와 테이블의 외래 키 매핑
  • 방향(Direction) : 단방향, 양방향
  • 다중성(Multiplicity) : 다대일(N:1), 일대다(1:N), 일대일(1:1), 다대다(N:M)
  • 연관관계의 주인(Owner) : 객체 양방향 연관관게는 관리주인이 필요

연관관계가 필요한 이유

객체지향 설계의 목표는 자율적인 객체들의 협력 공동체를 만드는 것이다.

객체를 테이블에 맞추어 모델링

@Column(name = "TEAM_ID")
private Long teamId;
  • 식별자로 다시 조회하기 때문에 객체지향적인 방법은 아니다.

  • 멤버 ID를 통해 멤버 조회 -> 해당 멤버의 팀 ID 조회 -> 조회한 팀 ID를 통해 팀 조회

  • 테이블은 외래 키로 조인을 사용해서 연관 테이블을 찾는다.

  • 객체는 참조를 사용해서 연관된 객체를 찾는다.

객체 지향 모델링 (ORM)

@ManyToOne
@JoinColumn(name = "TEAM_ID")
private Team team;

DB에서의 TEAM_ID(FK)와 Team 객체를 위와 같이 연결해주면 끝!

양방향 연관관계와 연관관계의 주인

테이블과 객체의 차이

  • 테이블의 연관관계는 외래 키 하나로 양방향이 모두 존재한다.
  • 객체는 서로의 클래스를 포함시켜야 양방향이 가능하다.

양방향 매핑

public class Team {
	@OneToMany(mappedBy = "team")
	private List<Member> members = new ArrayList<>();
}

연관관계의 주인과 mappedBy

객체와 테이블이 관계를 맺는 차이

  • 객체 연관관계 : 2개
    - 회원 -> 팀 1개 (단방향)
    • 팀 -> 회원 1개 (단방향)
  • 테이블 연관관계 : 1개
    - 회원 <-> 팀 1개 (양방향)

객체의 양방향 관계

  • 객체의 양방향 관계는 사실 단방향 2개이다.

테이블의 양방향 관계

  • 테이블은 외래 키 하나로 양방향 연관관계를 가진다.

둘 중 하나로 외래 키를 관리해야 한다.

  • 정보가 변경될 때, Member의 Team을 변경할지 Team의 Member를 변경할지..

연관관계의 주인(Owner)

  • 객체의 두 관계중 하나를 연관관계의 주인으로 지정
  • 연관관계의 주인만이 외래 키를 관리(등록, 수정)
  • 주인이 아닌쪽은 읽기만 가능
  • 주인은 mappedBy 속성 사용X, 주인이 아닌 경우는 mappedBy 속성 사용

누구를 주인으로?

  • 외래 키가 있는 곳을 주인으로 정한다. (MEMBER 테이블에 TEAM_ID 라는 외래 키가 존재함)
  • 진짜 매핑 - 연관관계의 주인 (Member.team)
  • 가짜 매핑 - 주인의 반대편 (Team.members)

주의점

순수 객체 상태를 고려해서 항상 양쪽에 값을 설정하자

  • 연관관계의 주인이 아닌 가짜매핑에 접근하여 값을 넣을 경우 주인의 값에는 null이 들어간다.
  • 주인과 주인이 아닌 곳 모두 값을 넣어줘야 한다.
    - 영속성 컨텍스트를 초기화 했을 경우, 1차 캐시가 아닌 DB에서 조회하기 때문에 주인에만 값이 있어도 알아서 가져온다.
    • 영속성 컨테스트를 초기화하지 않을 경우, findTeam은 1차 캐시에 저장된 순수한 team 객체이다.
    • member.setTeam(team)을 하고 team.add(member)를 하지 않는 경우, member에는 team이 저장되지만 team 객체를 가져온 findTeam에는 member가 없기 때문에 조회해도 값이 출력되지 않는다.

연관관계 편의 메서드 작성

  • 항상 양쪽에 값을 넣어야 하니까 이를 편리하게 하기 위해 메서드 작성
  • Member 클래스의 setter에 team.add(member) 추가
  • setTeam이 아닌 changeTeam으로 이름을 바꾸어 기능이 추가되었다는 것을 명시
  • Member, Team 클래스 둘 중 하나에 작성

양방향 매핑시 무한루프

  • Member 클래스 toString()의 team.toString() -> team.toString()의 Members.t oString() -> Member 클래스 -> ...
  • controller에서 entity를 직접 반환할 경우 JSON으로 바꾸는 과정
    - Member클래스를 JSON으로 바꿀 때 안에 있는 Team 객체도 JSON -> Team 객체 안의 Members에 있는 모든 Member 클래스 JSON -> Member 클래스 안의 Team 객체 JSON -> ...
    • entity가 아닌 DTO를 반환하자

정리

  • 단방향 매핑만으로도 이미 연관관계 매핑이 완료된 것이다.
    - 객체, 테이블 설계시 외래 키를 보고 단방향 매핑부터 먼저 한다.
    • 양방향 매핑은 반대 방향으로 조회(객체 그래프 탐색) 기능이 추가된 것 뿐이다.
    • 단방향 매핑을 모두 잘 끝내고 양방향은 필요할 때 추가해도 된다. (member가 team을 굳이 알 필요는 없다.)
  • OneToMany 할 경우 new로 생성자를 초기화해주는 이유는 NPE 방지

0개의 댓글