[JPA] 5. 연관관계 매핑 기초

지니🧸·2023년 2월 10일
0

Spring Boot & JPA

목록 보기
12/35

본 문서는 인프런의 자바 ORM 표준 JPA 프로그래밍 - 기본편 (김영한) 강의를 공부하며 작성한 개인 노트입니다.

용어

  • 방향, Direction: 단방향, 양방향
  • 다중성, Multiplicity: 다대일(N:1), 일대다(1:N), 일대일(1:1), 다대다(N:M) 이해
  • 연관관계의 주인, Owner: 객체 양방향 연관관계는 관리 주인이 필요

🧞 단방향 연관관계

  • 회원과 팀은 다대일 관계
  • setTeamId로 회원 객체에 팀 지정
  • join으로 연관된 회원/팀 조인
select * from member m
join team t on m.team_id = t.team_id

객체를 테이블에 맞춘 데이터 중심 모델링은 협력 관계를 만들 수 없다

  • 테이블: 외래키 기반 조인으로 연관된 테이블 찾음
  • 객체: 참조로 연관된 객체 찾음

단방향 연관관계

<객체 지향 모델링>

Member class

@Entity
public class Member {
	...
    @ManyToOne 
    @JoinColumn(name = "TEAM_ID")
    private Team team;
}

Main class

Team team = new Team();
... // 팀 정보 설정
em.persist(team);
Member member = new Member();
... // 회원 정보 설정
member.setTeam(team);
em.persist(member);
...
Member findMember = em.find(Member.class, member.getId());
Team findTeam = findMember.getTeam(); // 객체 그래프 탐색

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


양방향 연관관계 - 회원에서 팀 연결, 팀에서 회원 연결

Team class

@Entity
public class Team {
	
    @Id @GeneratedValue
    @Column(name = "TEAM_ID")
    private Long id;
    ...
    
   
   @OneToMany(mappedBy = "team")
   private List<Member> members = new ArrayList<>();
   ...

}
  • 회원:팀 = 다대일
  • 팀:회원 = 일대다
  • @OneToMany(mappedBy = "변수명"): Member class의 연결되는 변수명
    • mappedBy

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

  • 객체 연관관계 > 2개
    • 회원 > 팀 연관관계 (단방향) - 1
    • 팀 > 회원 연관관계 (단방향) - 1
  • 테이블 연관관계 > 1개
    • 회원 테이블의 외래키 (팀 테이블의 PK)로 연결 - 1


team 연관관계 또는 members 연관관계 중 하나로 외래 키를 관리해야 함

  • 디비 입장에서는 어느 방법이든 상관 없음
  • 둘 중 주인을 정하는 것

연관관계의 주인, Owner

양방향 매핑 규칙

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

누구를 주인으로?
- 외래 키가 있는 쪽을 주인으로
- 다 인쪽

  • 외래키가 있는 쪽이 다(N) 임 (예) 회원:팀 = 다대일
  • 비즈니스적으로 중요한 것과는 무관 (예) 자동차와 바퀴로 치면 바퀴가 다 임

양방향 매핑시 가장 많이 하는 실수

연관관계의 주인에 값을 입력하지 않는 실수

  • 회원이 연관관계의 주인이기 때문에 member.setTeam(team)으로 연관관계 설정해야 함
  • 객체 관계를 고려하면 양쪽에 값을 입력하는게 맞음
    • JPA/디비 상으로는 em.flush() & em.clear()가 있으면 주인에만 입력해도 작동 됨
      • flush & clear가 있으면 1차 캐시가 사라져서 디비까지 가서 정보를 가져와서 연관관계 인식 가능
    • team에 member를 추가하지 않고 member 정보를 메모리에 저장하지 않고 가져오게 되면 에러

주의사항

  • 순수 객체 상태를 고려하여 항상 양쪽에 값 설정
  • 연관관계 편의 메소드 생성하자
    @Entity 
    public class Member {
    		...
          public void changeTeam(Team team) {
          	this.team = team;
              team.getMembers().add(this);
          }
    }
    • 회원을 셋팅하면 팀도 알아서 셋팅되도록
    • 팀에 회원추가하는 메서드 OR 회원에 팀을 지정하는 메서드 중 하나만 정해서 구현
  • 양방향 매핑시 무한 루프 조심하자 (예) toString(), lombok, JSON 생성 라이브러리
    • Member 클래스에 toString을 만들면 team 변수의 toString()을 호출 > Team에서 toString을 호출하면 member의 toString 호출 > 무한루프
    • toString & Lombok은 지양하자
    • 컨트롤러에 entity 반환하지 말자 > entity는 DTO로 변환하여 반환하자

양방향 매핑 정리

  • 단방향 매핑만으로도 이미 연관관계 매핑은 완료
    • 설계 중에는 단방향 매핑만 해야함
  • 양방향 매핑은 반대 방향으로 조회 (객체 그래프 탐색) 기능이 추가된 것 뿐
  • 단방향 매핑을 잘하고 양방향은 필요시 추가
    • 테이블에 영향 X

🦬 실전 예제 2 - 연관관계 매핑 시작

참조를 사용한 연관관계

profile
우당탕탕

0개의 댓글