JPA 연관관계 매핑

jyKim·2023년 6월 14일
0

JPA

목록 보기
7/7

단반향 연관관계

  • 한쪽 엔티티에서만 일방적으로 관계를 맺는 경우 아래는 다대일(N:1)관계의 예시
  • 한쪽 엔티티가 다른 엔티티를 참조로 가지고 있다.
  • 한쪽 방향으로만 객체 그래프 탐색이 가능.
// 멤버
public class Member {
   @Id
   @Column(name = "MEMBER_ID")
   private Long id;

   @Column(name="USERNAME")
   private String username;

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

   @Enumerated(EnumType.STRING)
   private RoleType roleType;
}

// 팀
public class Team {
   @Id @GeneratedValue
   @Column(name =  "TEAM_ID")
   private Long id;

   private String name;
}

// 사용 예시
public Member createMember(String name, RoleType roleType, Long id){
   Member member = new Member();
   Team team = teamRepository.findById(id).isPresent() ? teamRepository.findById(id).get() : null;

   member.setUsername(name);
   member.setTeam(team);
   member.setRoleType(roleType);
   
   String teamName = member.getTeam().getName();

   return memberRepository.save(member);
}

양방향 연관관계

  • 테이블의 연관관계는 방향성이 존재하지 않는다. 따라서 양방향 연관관계라고 할 수 있으며, 외래키를 통해 JOIN을 수행할 경우 양쪽의 테이블 모두 조회 가능하다.
  • 반대 방향으로 객체 그래프 탐색이 가능하다.
  • 단방향 매핑만으로도 연관관계 매핑은 완료된 것 -> 설계 시 단방향 매핑만으로 설계를 끝내고, 양방향 매핑을 사용하면 안된다.
  • OneToMany의 경우 mappedBy를 통해 반대편 테이블의 어떤 컬럼과 연결되는지 알려주어야 한다.(연관관계의 주인을 지정한다.)
  • ManyToOne의 경우 JoinColumn을 통해 조인할 컬럼(외래키)를 알려주어야 한다.
  • JPQL에서 반대 방향 조회가 필요한 경우가 많다.
  • 단방향 매핑을 잘 해놓고, 양방향 매핑은 필요할 때만 추가한다.(테이블에 영향을 주지 않음)
 // 멤버
 public class Member {
    @Id
    @Column(name = "MEMBER_ID")
    private Long id;

    @Column(name="USERNAME")
    private String username;

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

    @Enumerated(EnumType.STRING)
    private RoleType roleType;
}

// 팀
public class Team {
    @Id @GeneratedValue
    @Column(name =  "TEAM_ID")
    private Long id;

    private String name;
    
    @OneToMany(mappedBy = "team")
    private List<Member> members = new ArrayList<>();
}

// 사용 예시
public Member createMember(String name, RoleType roleType, Long id){
    Member member = new Member();
    Team team = teamRepository.findById(id).isPresent() ? teamRepository.findById(id).get() : null;

    member.setUsername(name);
    member.setTeam(team);
    member.setRoleType(roleType);
   
    List<Member> members = team.getMembers();
    for(Member m : members){
    	System.out.println("member name = " + m.getUsername);
    }

    return memberRepository.save(member);
 }

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

  • 객체 = 2개
    1. 회원 -> 팀 연관관계 1개 (단방향)
    2. 팀 -> 회원 연관관계 1개 (단방향)
    • 객체의 양방향 관계는 양방향 관계가 아닌, 서로 다른 단방향 관계 2개이다.
    • 객체를 양방향으로 참조하려면 단방향 연관관계를 2개 만들어야한다.
  • 테이블 = 1개
    1. 회원 <-> 팀 연관관계 1개 (양방향)
    • 외래키 하나로 두 테이블의 연관관계를 관리(양쪽으로 조인 가능)

연관관계의 주인

  • 위와 같은 객체와 테이블 사이의 관계에서 차이로 인하여, 양방향 연관관계에서는 회원과 팀 사이에서 맺어진 2개의 연관관계 중 하나를 통해 외래키의 관리가 필요하다.
  • 따라서, 객체의 두 관계 중 하나를 연관관계의 주인으로 지정해야한다.

연관관계 주인의 특징은 아래와 같다.
1. 연관관계의 주인만이 외래 키를 관리(등록, 수정)
2. 주인이 아닌 쪽은 읽기만 가능하다.
3. 주인은 mappedBy 속성을 사용하지 않는다.
4. 주인이 아닐 경우 mappedBy 속성으로 주인을 지정한다.
5. 외래키가 있는 곳을 주인으로 정한다.
6. 예시의 경우 Member.team이 주인

  • DB기준으로 다대일(N:1), 일대다(1:N) 관계에서는 다(N)쪽이 연관관계의 주인이 된다.
  • JPA에서는 @ManyToOne 어노테이션 을 가진 엔티티가 주인이 된다.

양방향 매핑 시 주의사항

  • 양방향 매핑시에는 연관관계의 주인에 값을 입력하여야 한다.(순수 객체 상태를 고려하여 항상 양쪽 다 값을 입력해야한다.)
  • 양방향 매핑시 무한 루프 조심 -> 순환참조 발생 (toString(), lombok, JSON 생성 라이브러리 등등)
  • 컨트롤러에서는 Entity를 반환하지 말 것 -> DTO로 변환하여 반환.
profile
백엔드애옹

0개의 댓글