Home 단방향 연관관계
Post
Cancel

단방향 연관관계

단방향 연관관계

단방향 연관관계는 1 : N(1대다)인 경우를 말한다. 이 경우는 한 쪽의 엔티티가 관계를 맺은 엔티티 쪽의 여러 객체를 가질 수 있다는 것을 의미한다.

  • 팀은 다수의 회원을 포함하고 있다.
  • 하나의 주문에는 다수의 주문상품이 포함된다.
  • 상위 카테고리는 다수의 하위 카테고리를 가지고 있다.

테이블 연관관계

테이블은 외래 키를 활용하여 연관관계를 맺는다. 그리고 외래 키를 통해서 테이블을 조인할 수 있는데 외래 키가 두 테이블 중 어디에 있든 조인이 가능하다. (양방향 관계)

캡처

1
2
3
4
5
6
7
8
9
select
    *
from member m
join team t on t.team_id = m.team_id

select
    *
from team t
join member m on m.team_id = t.team_id

객체 연관관계

객체의 경우 필드를 이용하여 연관관계를 맺는다. 객체는 테이블과 다르게 연관관계 필드가 있는 객체에서만 접근이 가능하다. (단방향 관계)

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
class Member {
    private Long memberId;

    private Team team;

    private String username;
}

class Team {
    private Long teamId;

    private String name;
}

Member member = new Member();
member.getTeam();

Member에서는 Team에 접근할 수 있지만 Team은 member의 정보가 없기 때문에 접근할 수 없다.

객체 연관관계 vs 테이블 연관관계

객체

  • 객체는 참조(주소)로 연관관계를 맺는다.
  • 참조를 사용하는 객체의 연관관계는 단방향이다.

테이블

  • 테이블은 외래 키로 연관관계를 맺는다.
  • 외래 키를 사용하는 테이블의 연관관계는 양방향이다.

객체 관계 매핑

위에서 객체와 테이블의 연관관계 방법 및 차이점을 알아보았다. 이제 JPA를 활용하여 객체와 테이블을 매핑하는 방법을 알아보자.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
@Entity
class Member {
    @Id1
    private Long memberId;

    // 연관관계 매핑
    @ManyToOne
    @JoinColumn(name = "team_id")
    private Team team;

    private String username;
}

class Team {
    private Long teamId;

    private String name;
}

@ManyToOne

이름 그대로 다대일(N:1) 관계를 나타내는 매핑 정보이다. 회원과 팀은 다대일 관계에 있다. JPA에서는 연관관계를 표현할 때 이러한 다중성을 나타내는 어노테이션을 필수로 사용해야한다.

@ManyToOne 속성

속성기능기본값
optionalfalse로 설정하면 연관된 엔티티가 항상 있어야 한다.true
fetch글로벌 페치 전략을 설정한다.FetchType.EAGER
cascade영속성 전이 기능을 사용한다. 
targetEntity연관된 엔티티의 타입 정보를 설정한다. 이 기능은 거의 사용하지 않는다.
컬렉션을 사용해도 제네릭으로 타입 정보를 알 수 있다.
 

@ManyToOne과 함께 사용된 어노테이션인 @JoinColumn은 외래 키를 매핑하기 위해 사용한다. 즉, @JoinColumn(name = "team_id")에서 name의 값인 team_id는 외래키를 나타낸다. 해당 어노테이션은 생략이 가능하다.

@JoinColumn 속성

속성기능기본값
name매핑할 외래 키 이름필드명 + _ + 참조하는 테이블의
기본 키 컬럼명
referencedColumnName외래 키가 참조하는 대상 테이블의 컬럼명참조하는 테이블의 기본 키 컬럼명
foreignKey(DDL)외래 키 제약조건을 직접 지정할 수 있다.
이 속성은 테이블을 생성할 때만 사용한다.
 
unique
nullable
insertable
updatable
columnDefinition
table
@Column의 속성과 동일 

@JoinColumn 생략 시

@JoinColumn을 생략하게 되면 외래 키를 찾을 때 기본 전략을 사용한다.

1
2
@ManyToOne
private Team team;

기본 전략: 필드명(tema) + _ + 참조하는 테이블의 컬럼명(team_id) -> team_team_id

연관관계 사용

저장

연관관계를 매핑한 엔티티를 어떻게 저장하는지 예제로 알아보자.

1
2
3
4
5
6
7
8
9
10
11
public void save() {

    // 팀1 저장
    Team team1 = new Team("team1", "팀1");
    em.persist(team1);

    // 회원1 저장
    Member member1 = new Member("member1", "회원1");
    member1.setTeam(team1); // 연관관계 설정
    em.persist(member1);
}

연관관계를 매핑하기 위해 Member를 생성 후 member가 가지고 있는 setTeam(team1) 메소드로 Team을 설정하는 것을 볼 수 있다.

Member 엔티티에 Team 필드에 값이 세팅되어 있는 상태로 Member가 저장되면 JPA가 참조하는 팀의 식별자를 외래 키로 사용하여 적절한 등록 쿼리를 생성한다.

조회

연관관계가 있는 엔티티를 조회하는 방법은 크게 2가지가 있다.

  • 객체 그래프 탐색 (객체 연관관계를 사용한 조회)
  • 객체지향 쿼리(JPQL) 사용

객체 그래프 탐색

1
2
Member member = em.find(Member.class, "member1");
Team team = member.getTeam(); // 객체 그래프 탐색

위 코드와 같이 객체를 통해 연관된 엔티티를 조회하는 것을 객체 그래프 탐색이라 한다.

수정

연관관계를 수정하는 방법을 코드를 통해 알아보자.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
public void update() {
    // 팀1 저장
    Team team1 = new Team("team1", "팀1");
    em.persist(team1);

    // 회원1 저장
    Member member1 = new Member("member1", "회원1");
    member1.setTeam(team1); // 연관관계 설정
    em.persist(member1);

    // 새로운 팀2 생성
    Team team2 = new Team("team2", "팀2");
    em.persist(team2);

    // 회원1 조회
    Member find = em.find(Member.class, "member1");
    // 회원1에 팀2 설정
    member.setTeam(team2);
}

영속상태의 Member를 조회 후 새로운 연관관계인 Team2로 값을 변경하게 되면 이후 트랜잭션을 커밋할 때 플러시가 발생되고 변경감지 기능이 동작하여 연관관계가 변경된다.

제거 (연관관계 제거)

1
2
3
4
public void delete() {
    Member member1 = em.find(Member.class, "member1");
    member1.setTeam(null);
}

영속상태의 Member를 조회 후 Team 값을 null로 변경하면 연관관계를 제거할 수 있다.

연관된 엔티티 삭제

만약 연관된 엔티티를 삭제하려면 기존에 있던 연관관계를 먼저 제거후 삭제를 해야한다. 그렇지 않으면 외래 키 제약조건으로 인해 데이터베이스 오류가 발생하게 된다. 예제의 경우로 다시 설명하면 Team1을 삭제하기 위해서는 Member1과 Team1의 연관관계를 우선 삭제해야 한다.

1
2
member1.setTeam(null); // member1과 team1의 연관관계 제거
em.remove(team1); // team1 삭제

참고

This post is licensed under CC BY 4.0 by the author.

필드와 컬럼 캐핑

양방향 연관관계

Comments powered by Disqus.