스터디/JPA

JPA 스터디2 - 5

라퐁 2025. 8. 10. 16:10

객체를 테이블에 맞추어 모델링

예제 시나리오는 다음과 같다.

  • 회원과 팀이 있다.
  • 회원은 하나의 팀에만 소속될 수 있다.
  • 회원과 팀은 다대일(N:1) 관계다.
//회원 객체
@Entity
public class Member {

    @Id @GeneratedValue
    private Long id;

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

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

//팀 객체
@Entity
public class Team {

    @Id @GeneratedValue
    private Long id;

    private String name;
    ...
}

 

회원과 팀 객체를 만들고 회원과 팀을 저장하는 샘플 코드를 작성한다.

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

//회원 저장
Member member = new Member();
member.setName("member1");
member.setTeamId(team.getId());
em.persist(member);

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

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

 

객체는 참조를 사용해 연관된 객체를 찾고, 테이블은 외래키(Foreign Key)로 조인을 사용해 연관된 테이블을 찾는다. 이런 객체와 테이블의 차이가 있기 때문에, 객체를 테이블에 맞추어 테이블 중심으로 모델링하면 협력 관계를 만들 수 없다.

단방향 연관관계

객체의 참조와 테이블의 외래키를 매핑한다.

//회원 객체
@Entity
public class Member {
    ...
    //@Column(name = "TEAM_ID")
    //private Long teamId;

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

 

회원 객체의 team 속성을 팀 객체로 변경하고, @ManyToOne@JoinColumn 어노테이션을 붙여준다. @ManyToOne은 회원과 팀이 N:1 관계이기 때문에 회원 객체 기준 '다'이기 때문에 사용한다.

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

양방향 연관관계

앞에서 회원 객체 -> 팀 객체로 N:1 단방향 연관관계를 설정하였다.

@Entity
 public class Team {
     ...
     @OneToMany(mappedBy = "team")
     List<Member> members = new ArrayList<Member>();
    ...
 }

팀 객체 -> 회원 객체 1:N 단방향 연관관계를 추가로 설정한다. 이렇게 양방향 연관관계가 된다.

연관관계의 주인과 mappedBy

객체와 테이블이 관계를 맺는 방법에는 차이가 있다. 앞의 예시에서 객체 기준 연관관계는 2개로 '회원 객체 -> 팀 객체 단방향 연관관계'와 '팀 객체 -> 회원 객체 단방향 연관관계'가 있고, 테이블 기준 연관관계는 '회원 테이블 <-> 팀 테이블 양방향 연관관계'다. 객체에서도 양방향 연관관계로 얘기하고 있지만, 사실은 서로 다른 단방향 연관관계 2개인 것이다. 객체를 양방향으로 참조하려면 이런식으로 만들어야한다. 하지만 테이블은 외래키 하나로 연관관계를 관리할 수 있다.

 

연관관계에는 주인(Owner)가 필요하다. 객체의 두 관계 중 하나를 연관관계의 주인으로 지정하는데, 주인만 외래키를 관리(등록, 수정)하고 주인이 아닌 쪽은 읽기만 가능하다. mappedBy는 주인이 아닌 쪽이 주인을 지정하기 위해 사용한다. 주인의 선정은 일반적으로 외래키가 있는 곳을 주인으로 한다. 또한 순수 객체 상태를 고려해서 항상 양쪽에 값을 설정하는 것이 좋다(연관관계 편의 메소드 등 사용).

 

단방향 매핑만으로도 이미 연관관계 매핑은 완료된다. 양방향 매핑은 반대 방향으로 조회(객체 그래프 탐색) 기능이 추가된 것 뿐이다. JPQL 사용시에도 역방향으로 탐색을 할 일이 많다. 기본적으로 단방향 매핑을 잘 하고, 양방향 매핑을 필요할 때 추가해도 된다.

 

https://github.com/hongbre/jpa-basic/tree/main

 

GitHub - hongbre/jpa-basic

Contribute to hongbre/jpa-basic development by creating an account on GitHub.

github.com