[JPA] 연관 관계 매핑 (JPA 기본편 by 김영한)

kimdoha·2023년 8월 29일
1

[JPA]

목록 보기
5/8
post-thumbnail

연관관계 매핑

객체와 관계형 DB의 테이블 연관관계의 차이를 이해하는 것이 중요합니다. 객체를 테이블에 맞추어 모델링을 하게 되면 아래와 같이 모델링됩니다.

Association-Mapping-1

  • 참조 대신에 외래 키를 그대로 사용

    @Entity
    public class Member {
        @Id
        @GeneratedValue
        @Column(name = "MEMBR_ID")
        private Long id;
    
        private String name;
    
        @Column(name = "TEAM_ID")
        private Long teamId;
    }
  • 외래 키 식별자를 직접 다룸

    // 팀 저장
    Team team = new Team();
    team.setName("teamA");
    em.persist(team);
    
    // 회원 저장
    Member member = new Member();
    member.setName("memberA");
    member.setTeamId(team.getId());
    em.persist(member);
    
  • 식별자로 다시 조회 (객체 지향적인 방법 X)

    // 조회
    Member findMember = em.find(Member.class, member.getId());
    
    // 연관관계가 없음
    Team findTeam = em.find(Team.class, team.getId());

즉, 객체를 테이블에 맞추어서 데이터 중심의 모델링을 하면, 객체 간의 협력 관계를 만들 수 없습니다. 테이블의 경우 FK(Foreign Key)로 JOIN을 사용해서 연관된 테이블을 만들고, 객체의 경우 참조를 사용해서 연관된 객체를 찾을 수 있어야 합니다.

단방향 연관관계

따라서 JPA에서는 객체의 연관관계를 사용하여 객체 지향 모델링을 지원합니다.
회원 Entity와 Entity가 N:1 관계로 단방향 참조하는 것을 살펴보겠습니다.

Association-Mapping-2

  • 회원 Entity

    @Entity
    public class Member {
    
        @Id
        @GeneratedValue
        private Long id;
    
        private String name;
    
        @ManyToOne
        @JoinColumn(name = "TEAM_ID")
        private Team team;
    }

    회원 엔터티와 팀 엔터티가 N : 1 (다대일) 관계일 때, 단방향 참조 시 객체 연관관계와 테이블 연관관계를 도식으로 나타내면 다음과 같습니다.
    Assocation-Mapping-2

  • 연관관계 저장

    // 팀 저장
    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);

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

이번 예시는 회원 Entity와 Entity가 N:1 관계로 서로를 양방향 참조하는 것을 살펴보겠습니다.

Assocation-Mapping-3

  • 회원 Entity

    @Entity
    public class Member {
        
        @Id
        @GeneratedValue
        private Long id;
    
        private String name;
    
        @ManyToOne
        @JoinColumn(name = "TEAM_ID")
        private Team team;
    }
  • 팀 Entity

    @Entity
    public class Team {
        
        @Id
        @GeneratedValue
        private Long id;
    
        private String name;
    
        @OneToMany(mappedBy = "team")
        private List<Member> members;
    }

회원 Entity는 Team 객체 Field를 갖고, 팀 Entity는 Member 객체 Field를 갖습니다. 이때 회원과 팀은 N:1 다대일 관계이므로 @ManyToOne, @OneToMany 어노테이션을 설정합니다. 실제 서비스에서는 양방향 참조일 때 연관 관계가 더 복잡해지고 비즈니스 로직이 어렵게 될 수 있습니다. 양방향 참조 보다는 @ManyToOne 단방향 참조를 하는 것이 바람직합니다.

연관관계의 주인과 mappedBy
두 Entity가 주어졌을 때, 연관관계 주인을 정하는 것이 중요합니다.

연관관계의 주인은 사실 FK를 관리하는 Entity를 의미합니다.
객체의 양방향 관계는 사실 양방향 관계가 아니라 서로 다른 단뱡향 관계 2개입니다.

반면 테이블의 양방향 연관관계는 FK 하나로 두 테이블의 연관관계를 관리하여 조인으로 매핑합니다. 두 테이블 중 하나가 FK를 관리해야되며, 이는 곧 연관관계의 주인이 됩니다. 즉, 주인만이 FK를 관리하고 주인이 아닌 쪽은 읽기만 가능합니다.

  • 연관관계 주인 : mappedBy 속성 사용 X
  • 주인이 아닐 경우 : mappedBy 속성으로 주인 지정

Association-Mapping-4

회원 Entity와 팀 Entity 사이의 연관관계 매핑 예제를 추가적으로 응용하여 작성해보았습니다. 연관관계 매핑 실습 코드

회원 주문 실전 예제에 대한 연관관계 매핑 예제 코드입니다.
회원 주문 실전 예제
example

이제 연관관계의 유의할 점을 정리해보겠습니다.

다대일 [N:1]

  • @ManyToOne
    가장 많이 사용하는 연관관계

일대다 [1:N]

  • @OneToMany
    엔티티가 관리하는 외래 키가 다른 테이블에 있음
    일대다 매핑을 사용하기 원하면, 다대일 양방향 매핑을 사용하자

일대일 [1:1]

  • @OneToOne
    주 테이블이나 대상 테이블 중에 외래 키 선택 가능
    대신, 주 테이블에 외래 키가 있어야 한다.

다대다 [N:M]

  • @ManyToMany
    관계형 데이터베이스는 정규화된 테이블 2개로 다대다 관계를 표현할 수 없음
    연결 테이블용 엔티티 추가해서 일대다, 다대일 관계로 풀어내야함
    @ManyToMany -> @OneToMany, @ManyToOne

회원 상품 예제 실습에 주문과 배송 1 : 1 (@OneToOne) 관계와 N : M (@ManyToMany) 관계를 추가하여 실습을 진행했습니다.
다양한 연관관계 매핑 추가 예제

  • 주문과 배송은 1:1(@OneToOne)
  • 상품과 카테고리는 N:M(@ManyToMany)

연관관계 매핑 예제 Domain

0개의 댓글

관련 채용 정보