고급 매핑

JPA
  1. 1. 7.1 상속관계 매핑
    1. 1.1. 조인 전략
    2. 1.2. 단일 테이블 전략
    3. 1.3. 구현 클래스마다 테이블 전략
  2. 2. 7.2 @MappedSuperclass
  3. 3. 7.3 복합 키와 식별 관계 매핑
  • 상속 관계 매핑: 객체의 상속 관계를 데이터베이스에 어떻게 매핑하는지 다룬다.
  • @MappedSuperclass: 등록일, 수정일 같이 여러 엔티티에서 공통으로 사용하는 매핑 정보만 상속받고 싶으면 이 기능을 사용하면 된다.
  • 복합 키와 식별 관계 매핑: 데이터베이스의 식별자가 하나 이상일 때 매핑하는 방법을 다룬다. 그리고 데이터베이스 설계에서 이야기하는 식별 관계와 비식별 관계에 대해서도 다룬다.
  • 조인 테이블: 테이블은 외래 키 하나로 연관관계를 맺을 수 있지만 연관관계를 관리하는 연결 테이블을 두는 방법도 있다. 여기서는 이 연결 테이블을 매핑하는 방법을 다룬다.
  • 엔티티 하나에 여러 테이블 매핑하기: 보통 엔티티 하나에 테이블 하나를 매핑하지만 엔티티 하나에 여러 테이블을 매핑하는 방법도 있다. 여기서는 이 매핑 방법을 다룬다.

7.1 상속관계 매핑

JPA_Ex7_1.png

객체 상속 모델

JPA에서는 상속관계를 총 3가지로 제공

  • 조인 전략 : @Inheritance(strategy=InheritanceType.JOINED)
  • 단일 테이블 전략 : @Inheritance(strategy=InheritanceType.SINGLE_TABLE)
  • 구현 클래스마다 테이블 전략 : @Inheritance(strategy=InheritanceType.TABLE_PER_CLASS)

조인 전략

JPA_Ex7_2.png

부모 테이블의 기본 키를 받아서 기본 키 + 외래 키로 사용하는 전략
객체는 타입이 있지만 테이블은 없기에 DTYPE 이라는 컬럼을 구분 컬럼으로 사용해야함

단일 테이블 전략

JPA_Ex7_3.png

전략을 싱글테이블로 바꾸면된다.

추가로 자식엔티티에서 기본키 칼럼명이 다르면 @PrimaryKeyJoinColumn을 쓴다.

구현 클래스마다 테이블 전략

JPA_Ex7_4.png

이전략은 이름도 길어서 제일 안쓸거 같다.. 책에서는 데이터베이스 설계자와 ORM 전문가 둘 다 추천하지 않은 전략이라고 함

7.2 @MappedSuperclass

7.1에선 테이블과의 상속관계를 다뤘는데 이건 순수히 객체의 상속만을 할땐 @MappedSuperclass를 씀 추상 클래스와 비슷하다고 생각하면 됨

Copy of Untitled Diagram.png

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
@MappedSuperclass
public class BaseEntity {
@Id @GeneratedValue
private Long id;
private String name;
}

@Entity
public class Member extends BaseEntity {
//ID 상속
//NAME 상속
private String email;
}

@Entity
@AttributeOverride(name="id", column=@Column("MEMBER_ID"))
public class Seller extends BaseEntity {
//ID 상속
//NAME 상속
private String shopName;
}
1
2
@AttributeOverride
@AttributeOverrides

어노테이션을 통해 상속받은 칼럼명을 재정의 할수도 있음.

7.3 복합 키와 식별 관계 매핑

JPA_7_6.png

식별 관계

JPA_7_7.png

비식별 관계

@IdClass와 @EmbeddedId 방식 2가지가 존재 한다.

@IdClass는 테이블 친화적이고 @EmbeddedId는 객체 친화적

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
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
//식별관계 IdClass

@Entity
public class Parent {
@Id @Column(name="PARENT_ID")
private String id;

private String name;
}

@Entity
@IdClass(ChildId.class)
public class Child{
@Id
@ManyToOne
@JoinColumn(name="PARENT_ID")
public Parent parent;

@Id @Column(name="CHILD_ID")
private String ChildId;

private String name;
}

//자식ID

public class ChildId implements Serializable{
//Child.parent 매핑
private String parent;

//Child.childId 매핑
private String childId;

//equals, hashcode
}

@Entity
public class GrandChild{
@Id
@ManyToOne
@JoinColumns({
@JoinColumn(name="PARENT_ID")
,@JoinColumn(name="CHILD_ID")
})
private Child child;

@Id @Column(name="GRANDCHILD_ID")
private String id;

private String name;
}

//손자 ID
public class GrandChildId implements Serializable{
//GrandChild.child 매핑
private ChildId child;

//GrandChild.id 매핑
private String Id;

//equals, hashcode
}
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
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
//식별관계 EmbeddedId
@Entity
public class Parent {
@Id @Column(name="PARENT_ID")
private String id;

private String name;
}

@Entity
public class Child{
@EmbeddedId
private ChildId id;

//ChildId.prentId 매핑
@MapsId("prentId")
@ManyToOne
@JoinColumn(name="PARENT_ID")
public Parent parent;

private String name;
}

//자식ID
@Embeddable
public class ChildId implements Serializable{
//@MapsId("parentId")로 매핑
private String parentId;

@Column(name="CHILD_ID")
private String id;

//equals, hashcode
}

@Entity
public class GrandChild{
@EmbeddedId
GrandChildId id;

//GrandChildId.childId 매핑
@MapsId("childId")
@ManyToOne
@JoinColumns({
@JoinColumn(name="PARENT_ID")
,@JoinColumn(name="CHILD_ID")
})

private Child child;

private String name;
}

//손자 ID
@Embeddable
public class GrandChildId implements Serializable{
//@MapsId("childId") 매핑
private ChildId childId;

@Column(name="GRANDCHILD_ID")
private String Id;

//equals, hashcode
}
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
32
33
34
35
36
//비식별 관계
@Entity
public class Parent {
@Id @GeneratedValue
@Column(name="PARENT_ID")
private Long id;

private String name;
}

@Entity
public class Child{
@Id @GeneratedValue
@Column(name="CHILD_ID")
private Long id;

//ChildId.prentId 매핑
@ManyToOne
@JoinColumn(name="PARENT_ID")
public Parent parent;

private String name;
}

@Entity
public class GrandChild{
@Id @GeneratedValue
@Column(name="GRANDCHILD_ID")
private Long id;

@ManyToOne
@JoinColumn(name="CHILD_ID")
private Child child;

private String name;
}

식별 관계인 경우는 복합키가 필요함으로 키관련 클래스들도 생성해야 하지만 비식별관계는 키가 1개임으로 복합키클래스를 만들 필요가 없다.

참고로 키가 1개일 경우만 @GeneratedValue 를 사용할수 있다.

책에서는 비식별 관계를 사용하고 기본 키는 LONG 타입의 대리 키를 사용 하는것이 좋다고 소개 되어있습니다. 그 이유는 비즈니스와 관련이 없어 변경시에 유연한 대처가 가능 Long 타입의 경우 약 920경의 숫자를 담을수 있음.

나머지 조인테이블과 엔티티 하나에 여러 테이블 매핑이 있지만 비주류라서 소개 하지 않겠습니다.

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