본문 바로가기
JAVA

[JPA] JPA 다양한 연관관계 매핑 - 일대다 관계(1:N)

by 고 민 2024. 1. 14.
728x90
반응형

일대 다(1:N) 관계

JPA가 지원하는 연관관계 매핑중 일대 다 관계의 단방향, 양방향 특징과, 매핑 방법, 장단점에 대해 공부해 보려고 한다. 

다(N)보다 일(1)쪽에 비즈니스 로직의 비중이 높거나 중요도가 높은 경우 고려할 수 있는 관계이다. 
일대 다 관계에서는 일(1) 쪽인 TEAM의 members 프로퍼티와 MEMBER테이블의 MEMBER_ID를 매핑해 Team 엔티티의 members 프로퍼티에서 외래키를 관리한다. 

특징

  • 일(1)이 되는 쪽이 연관관계의 주인이 된다.
  • 테이블 관계는 항상 다(N) 쪽에 외래키가 있다.
  • 객체와 테이블의 페러다임 불일치로 인해 반대편 테이블의 외래 키를 관리한다. 
  • 일대 다 단방향, 일대 다 양방향 관계가 있지만 표준에서는 단방향만 지원한다. 
  • @JoinColumn 사용이 필수가 된다.

@OneToMany 

1:N 관계를 표현하기 위해선 엔티티의 외래키를 관리할 프로퍼티 위에 @OneToMany 어노테이션을 사용하여 관계를 명시한다. 1:N 관계에서 @JoinColumn을 사용해서 매핑할 컬럼을 명시하지 않은 경우 중간에 테이블 하나를 추가하는 조인 테이블 방식을 디폴트로 사용한다. 

아래 예제를 통해 알아보자 

@JoinColumn 사용하지 않은 경우 

@Entity
public class Team {

    @Id @GeneratedValue
    private Long id;

    private String name;

    @OneToMany
    private List<Member> members;
Hibernate: 
    
    create table Member (
       id bigint not null,
        TEAM_ID bigint,
        username varchar(255),
        primary key (id)
    )
Hibernate: 
    
    create table Team (
       id bigint not null,
        name varchar(255),
        primary key (id)
    )
    
 /*조인 테이블 방식의 테이블 생성 */
Hibernate: 
    
    create table Team_Member (
       Team_id bigint not null,
        members_id bigint not null
    )
    
Hibernate: 
    
    alter table Team_Member 
       add constraint UK_s2bdqsiefihvxghf2fujxn2eg unique (members_id)
Hibernate: 
    
    alter table Team_Member 
       add constraint FKbh0ppoyhmwjgigc2gs7lr1kcf 
       foreign key (members_id) 
       references Member
Hibernate: 
    
    alter table Team_Member 
       add constraint FK267gfjokmdychsnik3u313q5j 
       foreign key (Team_id) 
       references Team

 

@JoinColumn을  사용하지 않은 경우 create모드에서 MEMBER테이블과 TEAM 테이블 외에 자동으로 Team_meber라는 join테이블과 제약 조건을 생성하는 DDL이 실행 된 것을 볼 수 있다.

DB에도 TEAM_MEMBER 테이블 생성되어있다. 

 

따라서 참조 테이블 방식을 사용할 의도가 아니면 @JoinColumn 어노테이션에 매핑할 컬럼 을 반드시 명시해 주어야한다.

 

단점

  • FK(forigen key)를 관리하는 엔티티와 반대의 테이블이 매핑되어 동작이 직관적이지 않아 관리가 까다롭다.
    아래 코드에서 Team 엔티티에 Member를 추가하지만 실행 결과를 보면 Member 테이블의 memberId가 수정된다. 
    Team team = new Team();
    team.setName("teamA");
    em.persist(team);
    
    Member member = new Member();
    em.member
    em.persist(member);
    
    // 팀 엔티티에 member 정보 추가
    team.getMembers().add(member);​
    Hibernate: 
        /* insert hellojpa.Team
            */ insert 
            into
                Team
                (name, id) 
            values
                (?, ?)
    Hibernate: 
        /* insert hellojpa.Member
            */ insert 
            into
                Member
                (TEAM_ID, username, id) 
            values
                (?, ?, ?)
    Hibernate: 
        /* create one-to-many row hellojpa.Team.members */ update
            Member 
        set
            MEMBER_ID=? 
        where
            id=?​
  •  Team엔티티에서 참조 객체 Member를 다룰 때 update문이 추가적으로 발생하므로 결과가 같은 N:1 연관관계에 비해 성능적으로 떨어진다. 

일대 다(1:N) 관계 - 양방향 

JPA 표준에선 지원하지 않지만 엔티티 설정을 통해 양방향 관계와 동일하게 동작하도록 설정 할 수 있다. 

@JoinColumn(insertable = false, updatable = false)

Member 엔티티의 team 프로퍼티를 만들고  team의 Id를 참조 할 수 있도록 @ManyToOne 어노테이션을 명시한다. 
이 때 속성 값으로 insertable 과 updatable을 지정 할 수 있는데, 둘 다 false로 지정할 경우 프로퍼티를 통해 테이블의 쓰기와 수정이 불가능해져 양방향 연관관계와 동일해진다. 

@Entity
public class Member {


    @Id @GeneratedValue
    private Long id;

    @ManyToOne()
    @JoinColumn(name = "TEAM_ID", insertable = false, updatable = false)
    private Team team;

단 공식적으로 존재하는 방법이 아니고, N:1 양방향 관계 매핑으로 사용하는 것이 성능적으로 객체지향적으로 이점이 많기 때문에 양방향 엔티티를 사용하는 것이 바람직하다. 

728x90
반응형