공부/JPA

JPA 연관관계 매핑 - 단방향 연관관계

데부한 2022. 7. 1. 22:30
반응형

출처 : 자바 ORM 표준 JPA 프로그래밍 인프런 강의

 

JPA 게시글은 대부분 인프런의 김영한님의 강의인 '자바 ORM 표준 JPA 프로그래밍' 기반으로 내용을 정리했습니다.

 

단방향 연관관계

예제 시나리오

  • 회원과 팀이 존재한다.
  • 회원은 하나의 팀에만 소속될 수 있다.
  • 회원과 팀은 다대일 관계이다.

 

객체를 테이블화한 모델링

 

객체 클래스 생성(Member)


@Entity
public class Member {

    @Id @GeneratedValue
    @Column(name = "MEMBER_ID")
    private Long id;

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

    @Column(name = "TEAM_ID")
    private Long teamId;
    
    ...getter/setter 생략
}

 

객체 클래스 생성(Team)


@Entity
public class Team {

    @Id
    @GeneratedValue
    @Column(name = "TEAM_ID")
    private Long id;
    private String name;
    
    ...getter/setter 생략
}

 

실행 클래스

...생략
// 팀 저장
Team team = new Team();
team.setName("Team A");
em.persist(team);

// 회원 저장
Member member = new Member();
member.setUsername("member1");
member.setTeamId(team.getId()); // 이 부분이 애매하다.
em.persist(member);

// 조회
Member findMember = em.find(Member.class, member.getId());
Long findTeamId = findMember.getTeamId();
Team findTeam = em.find(Team.class, findTeamId);

tx.commit();
...생략

테이블에 맞춰 코드를 작성하면 객체지향스럽지 않다. 그리고 불필요하게 DB에 계속 접근하게 된다. 이렇게 불편하게 코딩하는 이유는 연관 관계가 없기 때문이다. 연관 관계가 없는 이유는 데이터 중심으로 모델링하여 협력 관계를 만들 수 없기 때문이다.

  • 테이블은 외래 키로 조인을 사용해서 연관된 테이블을 찾는다.
  • 객체는 참조를 사용해서 연관된 객체를 찾는다.
  • 테이블과 객체 사이에는 이런 큰 간격이 있다.

이런 문제점들로 인하여 객체를 중심으로 연관 관계를 맺어 코딩하는 것이 더 좋다.

 

 

객체 지향 모델링

 

객체 클래스(Member)


@Entity 
public class Member {

    @Id @GeneratedValue
    @Column(name = "MEMBER_ID")
    private Long id;

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

//    @Column(name = "TEAM_ID")
//    private Long teamId;

    @ManyToOne
    @JoinColumn(name = "TEAM_ID")
    private Team team;
    
    ...getter/setter 생략
}

기존 Team 테이블과 연관된 필드인 teamId를 주석처리하고 대신 team 필드를 추가했다.

  • @ManyToOne : 연관 관계를 표현한다. Member와 Team의 관계가 Member 입장에서 봤을 때 다대일이다. 고로 Member 필드에 ManyToOne 애노테이션을 붙인다.
  • @JoinColumn : 객체 지향 모델링을 봤을 때 Member는 TEAM_ID를 외래키로 가져 연관 관계를 나타낸다. 그러므로 TEAM_ID로 Member와 Team 객체에 연관 관계를 맺어준다.

 

실행 클래스

...생략

// 팀 저장
Team team = new Team();
team.setName("Team A");
em.persist(team);

// 회원 저장
Member member = new Member();
member.setUsername("member1");
member.setTeam(team);
em.persist(member);

// JOIN 쿼리를 보기 위해 
em.flush();
em.clear();

// 조회
Member findMember = em.find(Member.class, member.getId());
Team findTeam = findMember.getTeam();

tx.commit();

...생략

연관 관계가 없었던 맨 위에 코드와는 달리 조금 더 객체지향스럽게 느껴지는 코드이다. 위의 코드를 실행하면 다음과 같은 join 로그를 볼 수 있다.

Hibernate: 
    select
        member0_.MEMBER_ID as MEMBER_I1_0_0_,
        member0_.TEAM_ID as TEAM_ID3_0_0_,
        member0_.USERNAME as USERNAME2_0_0_,
        team1_.TEAM_ID as TEAM_ID1_1_1_,
        team1_.name as name2_1_1_ 
    from
        Member member0_ 
    left outer join
        Team team1_ 
            on member0_.TEAM_ID=team1_.TEAM_ID 
    where
        member0_.MEMBER_ID=?

 

반응형