티스토리 뷰

Books

[JPA] 연관관계 매핑이란.?

Aaron 2020. 12. 19. 23:06
반응형


| 연관관계 매핑



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


방향 (Direction) : 단방향, 양방향

방향은 객체관계에만 존재하고 테이블 관계는 항상 양방향

다중성 (Multiplicity) : 다대일, 일대다, 일대일, 다대다

연관관계의 주인 (owner) 



|| 단방향 연관관계



객체 연관관계 : 단방향 관계

 Member

Team 

 id

 Team team

 username

 id

 name


테이블 연관관계 : 양방향 관계

 Member

Team 

 id

 Team team

 username

 id

 name

 List members


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

- 객체는 참조(주소)로 연관관계 

ㄴ 연관 데이터 조회 시 .get() (참조) 사용 => 단방향

ㄴ 객체 그래프 탐색

- 테이블은 외래 키로 연관관계

ㄴ 연관 데이터 조회 시 JOIN 사용 => 양방향


* 객체를 양방향으로 참조하려면 단방향 연관관계를 2개 만들어야 함.



ㅇ 단방향 연관관계 매핑

> 회원 엔티티

1
2
3
4
5
6
7
8
9
10
11
12
13
14
@Entity
public class Member {
    @Id
    @Column(name = "MEMBER_ID")
    private String id;
 
    private String username;
 
    @ManyToOne
    @JoinColumn(name="TEAM_ID")
    private Team team;
 
    // ...
}
cs


> 팀 엔티티

1
2
3
4
5
6
7
8
9
10
@Entity
public class Team {
    @Id
    @Column(name = "TEAM_ID")
    private String id;
 
    private String name;
 
    // ...
}
cs


@ManyToOne : 다대일(N:1) 관계 매핑 정보

  연관관계 매핑 시 다중성 어노테이션은 필수

@JoinColumn(name="TEAM_ID") : 외래 키 매핑 (생량 가능)

 name 속성에는 매핑할 외래 키 이름 지정



||| JoinColumn



외래 키 매핑 시 사용


> 속성

name : 매핑할 외래 키 이름

default. [필드명]_[참조하는 테이블의 기본키 컬럼명]

referencedColumnName : 외래 키가 참조하는 대상 테이블의 컬럼명

 default. 참조하는 테이블의 기본 키 컬럼명

foreignKey (DDL) : 외래 키 제약조건을 직접 지정 (테이블 생성시에만 사용)


unique    : @Column 속성과 동일

nullable

insertable

updatable

columnDefinition

table


* @JoinColumn 생략 시 외래 키를 찾을 때 기본 전략을 사용

  [필드명]_[참조하는 테이블의 컬럼명]



||| ManyToOne



다대일 관계에서 사용


> 속성

optional : false 설정 시 연관된 엔티티가 항상 있어야 함. (default. true)

- EAGER 설정의 조인 전략

@ManyToOne, @OneToOne

- (optional = false) : 내부 조인

- (optional = true) : 외부 조인

@OneToMany, @ManyToMany

- (optional = false) : 외부 조인

- (optional = true) : 외부 조인

fetch : global fetch 전략 설정

@ManyToOne, @OneToOne(fetch = FetchType.EAGER) "즉시 로딩"

- 엔티티를 조회할 때 연관된 엔티티도 함께 조회

- 연관된 엔티티를 즉시 조회, hibernate는 가능하면 SQL 조인을 사용해서 한 번에 조회

- 객체가 계속 연결되어있을 경우 무한루프로 stack overflow 가능성..

@OneToMany, ManyToMany(fetch = FetchType.LAZY) "지연 로딩"

- 연관된 엔티티를 프록시로 조회, 프록시를 실제 사용할 때 초기화하면서 데이터베이스 조회

- 프록시 객체 : 지연 로딩 기능을 위해 실제 엔티티 객체 대신 데이터베이스 조회를 지연할 수 있는 가짜 객체

cascade : 영속성 전이 기능 사용

@OneToMany(mappedBy = "parent", cascade = CascadeType.PERSIST)

- 부모를 영속화할 때 연관된 자식들도 함께 영속화

- 부모 엔티티를 저장할 때 자식 엔티티도 함께 저장

, cascade = CascadeType.REMOVE 

- 부모 엔티티만 삭제하면 연관된 자식 엔티티도 함께 삭제

- CasecadeType 의 다양한 옵션

ALL,  // 모두 적용

PERSIST,  // 영속

MERGE,  // 병합

REMOVE,  // 삭제

REFRESH, 

DETACH

orphanRemoval : 부모 엔티티의 컬렉션에서 자식 엔티티의 참조만 제거하면 자식 엔티티가 자동으로 삭제(true)

- 참조하는 곳이 하나일 때만 사용 --> @OneToOne, @OneToMany

- CascadeType.Remove 설정과 동일


* cascadeType.All + orphanRemoval = true 일 경우, 부모 엔티티를 통해서 자식의 생명주기를 관리할 수 있음.

- 자식을 저장하려면 부모에 등록(CASECADE)

- 자식을 삭제하려면 부모에서 제거(removeObject)


1
2
3
4
5
@OneToMany
private List<Member> members; // 제네릭으로 타입 정보를 알 수 있음
 
@OneToMany(targetEntity=Member.class)
private List<Member> members; // 제네릭이 없으면 타입 정보를 알 수 없음
cs



|| 양방향 연관관계



단방향 연관관계에서 양방향 연관관계를 만들기 위해

객체에서는 컬렉션을 사용해준다.

 Member

Team 

 id

 Team team

 username

 id

 name

 List members


데이터베이스 테이블은 외래 키 하나로 양방향 조회가 가능하므로

추가 내용이 없음


1
2
3
4
5
6
7
8
9
@Id
@Column(name = "MEMBER_ID")
private String id;
 
private String username;
 
@ManyToOne
@JoinColumn(name="TEAM_ID")
private Team team;
cs



ㅇ 양방향 연관관계 매핑

> 회원 엔티티

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
@Entity
public class Member {
    @Id
    @Column(name = "MEMBER_ID")
    private String id;
 
    private String username;
 
    @ManyToOne
    @JoinColumn(name="TEAM_ID")
    private Team team;
 
    // 연관관계 설정
    public void setTeam(Team team) {
 
        // 기존 팀과 관계를 제거
        if (this.team != null) {
            this.team.getMembers().remove(this);
        }
        this.team = team;
        team.getMembers().add(this);
    }
 
    // ...
}
cs


> 팀 엔티티

1
2
3
4
5
6
7
8
9
10
11
12
13
@Entity
public class Team {
    @Id
    @Column(name = "TEAM_ID")
    private String id;
 
    private String name;
 
    @OneToMany(mappedBy = "team")
    private List<Member> members = new ArrayList<Member>();
 
    // ...
}
cs


@OneToMany 의 mappedBy 속성은 양방향 매핑일 때 사용,

   반대쪽 매핑의 필드 이름값으로 설정




|| 연관관계의 주인



객체에서의 연관관계는 "서로 다른 단방향 연관관계 2개" 와 같다.

단, 테이블은 외래 키 하나로 두 테이블의 연관관계를 관리한다.


엔티티를 양방향 연관관계로 설정하면 객체의 참조는 둘인데 외래 키는 하나가 되므로,

둘 사이에 차이가 발생한다.

=> 이러한 차이를 JPA에서는 두 객체 연관관계 중 하나를 정해서, 테이블의 외래키를 연관관계의 주인으로 관리


> 방향향 매핑의 규칙 : 연관관계의 주인

- 두 연관관계 중 하나의 연관관계의 주인으로 정해야 함

- 연관관계의 주인만이 데이터베이스 연관관계와 매핑되고 외래 키를 관리(등록, 수정, 삭제)할 수 있음

- 주인이 아닌 쪽은 읽기만 가능

- 연관관계 주인은 mappedBy 속성으로 정해줌


* 주인은 mappedBy 속성을 사용하지 않음

* 주인이 아니면 mappedBy 속성을 사용해서 속성의 값으로 연관관계의 주인을 지정해주어야 함


- 연관관계의 주인을 정한다는 것은 "외래 키 관리자를 선택하는 것"

  ㄴ 외래키(FK) 가 있는 테이블 객체가 연관관계의 주인


1
2
3
4
5
6
7
8
9
10
11
12
13
14
@Entity
public class Team {
    @Id
    @Column(name = "TEAM_ID")
    private String id;
 
    private String name;
 
    @OneToMany(mappedBy = "team"// 연관관계의 주인이 아님
    // 연관관계의 주인은 Member.team
    private List<Member> members = new ArrayList<Member>();
 
    // ...
}
cs


+


데이터베이스 테이블의 다대일, 일대다 관계에서는 항상 다 쪽이 외래 키를 가짐.

다 쪽인 @ManyToOne은 항상 연관관계의 주인이 되므로 mappedBy 설정이 불가 !





출처 : 자바 ORM 표준 JPA 프로그래밍

반응형
댓글
최근에 올라온 글
최근에 달린 댓글
Total
Today
Yesterday