티스토리 뷰

 

객체를 테이블에 맞추어 모델링(참조 대신 외래 키 사용)

Member, Team Class

@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("DongJun");
member.setTeamId(team.getId());
em.persist(member);

이 상황에서 회원의 팀을 찾으려면?

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

Long findTeamId = findMember.getId();
Team findTeam = em.find(Team.class, findTeamId);

연관관계가 없다면 member의 team을 가져오는데 계속 꺼내와야 한다.

member를 꺼내오고, teamId를 꺼내와서 다시 팀을 가져와야 한다.

회원의 팀을 가져오기 위해 많은 비용이 들고 객체 지향스럽지 않은 코드가 된다.

 

객체를 테이블에 맞추어 데이터(DB) 중심으로 모델링하면, 협력 관계를 만들 수 없다

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

 

단방향 연관관계

  • 객체 연관관계
    • 회원 객체(Member)는 Member.team 필드(멤버 변수)로 팀 객체와 연관관계를 맺는다
    • 회원 객체와 팀 객체는 단방향 관계이다. 회원은 Member.team 필드를 통해 팀을 알 수 있지만, 팀 객체로 소속된 회원들은 알 수 없다
  • 테이블 연관관계
    • 회원 테이블은 TEAM_ID 외래 키로 팀 테이블과 연관관계를 맺는다
    • 회원 테이블과 팀 테이블은 양방향 관계이다. 회원 테이블의 TEAM_ID 외래 키를 통해 회원과 팀을 조인할 수 있고, 반대로 팀과 회원도 조인 가능하다
  • 객체 연관관계와 테이블 연관관계의 차이
    • 참조를 통한 연관관계는 언제나 단방향이다. 객체 간에 연관관계를 양방향으로 만들고 싶으면 반대쪽에도 필드를 추가해서 참조를 보관해야 한다. 이렇게 양쪽에서 서로 참조하는 것을 양방향 연관관계라 한다
    • 하지만 정확히 이야기하면 이것은 양방향 관계가 아니라 서로 다른 단방향 관계가 2개인 것이다. 반면에 테이블은 외래 키 하나로 양방향으로 조인할 수 있다
  • 객체 연관관계 vs 테이블 연관관계
    • 객체는 참조로 연관관계를 맺는다
    • 테이블은 외래 키로 연관관계를 맺는다
    • 참조를 사용하는 객체의 연관관계는 단방향이다
    • 외래 키를 사용하는 테이블의 연관관계는 양방향이다

연관관계 사용

Member, Team Class

@Entity
public class Member {

  @Id @GeneratedValue
  private Long id;

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

  @ManyToOne
  @JoinColumn(name = "TEAM_ID")
  private Team team;
  
  // Getter, Setter ...
}

@Entity
public class Team {

  @Id @GeneratedValue
  private Long id;
  private String name;
  
  // Getter, Setter ...
}

연관관계 저장

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

//회원 저장
Member member = new Member(); 
member.setName("DongJun");
member.setTeam(team); //단방향 연관관계 설정, 참조 저장 
em.persist(member);

member에 teamId를 넣지 않고, team을 넣어준다.

참조로 연관관계 조회 - 객체 그래프 탐색

//조회
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);

@ManyToOne, @JoinColumn

@ManyToOne: 다대일(N:1) 관계라는 매핑 정보이다. 위에 회원과 팀은 다대일 관계이다. 연관관계를 매핑할 때 이렇게 다중성을 나타내는 어노테이션을 필수로 사용해야 한다.

속성 기능 기본값
optional false로 설정하면 연관된 엔티티가 항상 있어야 함 true
fetch 글로벌 패치 전략을 설정 @ManyToOne=FetchType.EAGER
@OneToMany=FetchType.LAZY
cascade 영속성 전이 기능을 사용  

 

@JoinColumn: 외래 키를 매핑할 때 사용.

속성 기능 기본값
name 매핑할 외래키 이름 "필드명" + "_" + "참조하는 테이블의 기본키 컬럼명"
referencedColumnName 외래키가 참조하는 대상 테이블의 컬럼명 참조하는 테이블의 기본키 컬러명
foreignKey(DDL) 외래키 제약조건을 직접 지정할 수 있다. 이 속성은 테이블을 생성할 때만 사용  

*JoinColumn 어노테이션은 생략 가능하다.

 생략하면 외래 키를 찾을 때 기본 전략을 사용

 

 

 

참고

자바 ORM 표준 JPA 프로그래밍(김영한)

링크
최근에 올라온 글
글 보관함
«   2025/05   »
1 2 3
4 5 6 7 8 9 10
11 12 13 14 15 16 17
18 19 20 21 22 23 24
25 26 27 28 29 30 31