[자바 ORM 표준 JPA 프로그래밍] 복합 키와 식별 관계 매핑

hyeseungS·2022년 4월 27일
0

7.3 복합 키와 식별 관계 매핑

이 장은 복합 키를 매핑하는 방법과 식별 관계, 비식별 관계를 매핑하는 방법에 대해 알아본다.

7.3.1 식별 관계 vs. 비식별 관계

  • 식별관계 : 부모 테이블의 기본 키를 내려받아서 자식 테이블의 기본 키 + 외래 키로 사용하는 관계

  • 비식별 관계 : 부모 테이블의 기본 키를 받아서 자식 테이블의 외래 키로만 사용하는 관계

  • 필수적 비식별 관계(Mandatory) : 외래 키에 NULL을 허용하지 않는다. 연관관계를 필수적으로 맺어야 한다.

  • 선택적 비식별 관계(Optional) : 외래 키에 NULL을 허용한다. 연관관계를 맺을지 말지 선택할 수 있다.

7.3.2 복합 키 : 비식별 관계 매핑

  • JPA에서 식별자를 둘 이상 사용하려면 별도의 식별자 클래스를 만들어야 함
    -> 식별자 필드가 2개 이상이면 별도의 식별자 클래스를 만들고 그곳에 식별자를 구분하기 위해 equals와 hashCode을 구현해 동등성 비교를 해야함.

  • @IdClass

    관계형 데이터베이스에 가까운 방법

- PARENT 테이블은 기본 키를 PARENT_ID1, PARENT_ID2로 묶은 복합 키로 구성
- 따라서, 복합 키를 매핑하기 위한 식별자 클래스

- @IdClass를 사용해 식별자 클래스인 ParentId 클래스를 식별자 클래스로 지정

[식별자 클래스의 조건] in @IdClass
- 식별자 클래스의 속성명 = 엔티티에서 사용하는 식별자의 속성명
- Serializable 인터페이스 구현
- equals, hashCode 구현
- 기본 생성자
- 식별자 클래스는 public 이어야함
  • 복합 키를 사용하여 엔티티를 저장
Parent parent = new Parent();
parent.setId1("myId1"); // 식별자
parent.setId2("myId2"); // 식별자
parent.setName("parentName");
em.persist(parent);
em.persist() 호출 
-> 영속성 컨텍스트에 엔티티를 등록하기 직전 내부에서 
   Parent.id1, Parent.id2 값 사용해 식별자 클래스인 ParentId 생성 
-> 영속성 컨텍스트의 키로 사용
  • 복합 키를 사용해 조회
ParentId parentId = new ParentId("myId1", "myId2");
Parent parent = em.find(Parent.class, parentId);
- 식별자 클래스인 ParentId를 사용해 엔티티 조회

- 부모 테이블의 기본 키 컬럼은 복합 키 -> 자식 테이블의 외래 키도 복합 키
- @JoinColumns : 외래 키 매핑 시 부모 테이블의 여러 컬럼을 매핑하기 위함
- @JoinColumns : 각각의 외래 키 컬럼 매핑
참고) @JoinColumn의 name 속성 = referencedColumnName 속성의 값
-> referencedColumnName 생략 가능
  • @EmbeddedId

    객체지향적인 방법

- 식별자 클래스 직접 사용
- @EmbeddedId 어노테이션
- @IdClass와는 다르게 식별자 클래스에 기본키 직접 매핑

[식별자 클래스의 조건] in @EmbeddedId
- @Embeddable 어노테이션
- Serializable 인터페이스 구현
- equals, hashCode 구현
- 기본 생성자
- 식별자 클래스는 public 이어야함
  • 복합 키를 사용하여 엔티티를 저장
Parent parent = new Parent();
ParentId parentId = new ParentId("myId1", "myId2");
parent.setId1(parentId); 
parent.setName("parentName");
em.persist(parent);
식별자 클래스 parentId를 직접 생성해서 사용
  • 복합 키를 사용해 조회
ParentId parentId = new ParentId("myId1", "myId2");
Parent parent = em.find(Parent.class, parentId);
조회코드는 @IdClass와 마찬가지로 식별자 클래스 parentId 직접 사용
  • 복합 키와 equals(), hashCode()

    복합 키는 equals(), hashCode() 필수로 구현

- id1과 id2 인스턴스 둘 다 myId1, myId2라는 같은 값을 가지고 있는데 
  인스턴스가 다름 
- 마지막 줄의 id1.equals(id2)는 참? 거짓?
  : equals()를 적절히 오버라이딩하지 않으면 결과는 거짓
  -> 자바의 모든 클래스는 기본으로 Object 클래스를 상속받는데 
     이 클래스가 제공하는 기본 equals()는 인스턴스 참조값 비교인 
     ==비교(동일성 비교)를 함
- 식별자 클래스는 보통 equals()와 hashCode()를 구현할 때 모든 필드 사용 
  • @IdClass vs @EmbeddedId
- @EmbeddedId 특정 상황에 JPQL이 더 길어질 수 있음
참고) 복합 키에는 @GenerateValue 사용 X

7.3.3 복합 키 : 식별 관계 매핑

  • @IdClass와 식별 관계
- 식별 관계는 기본 키 & 외래 키 같이 매핑
-> 식별자 매핑 : @Id, 연관관계 매핑 : @ManyToOne 사용
- Child 엔티티의 parent 필드는 @Id로 기본 키를 매핑하여 @ManyToOne과 @JoinColumn으로 외래 키 같이 매핑
  • @EmbeddedId와 식별 관계
- 식별 관계로 사용할 연관관계의 속성에 @MapsId를 사용함.
- @MapsId : 외래키와 매핑한 연관관계를 시본 키에 매핑하겠다.
- @MapsId 속성 값 : @EmbeddedId를 사용한 식별자 클래스의 기본 키 필드 지정

7.3.4 비식별 관계로 구현

위에서 들었던 식별 관계 테이블을 비식별 관계로 변경해보자!


- 매핑 쉽고 코드 단순
- 복합 키 없어서 복합 키 클래스를 만들지 않아도 됨

7.3.5 일대일 식별 관계

  • 자식 테이블의 기본 키 값으로 부모 테이블의 기본 키 값만 사용
  • 따라서, 부모 테이블의 기본 키가 복합 키 X -> 자식 테이블의 기본 키는 복합 키로 구성 X
- 식별자가 복합 키가 아닌 컬럼 하나면 @MapsId 사용하고 속성 값은 비움
- @MapsId는 @Id를 사용해서 식별자로 지정한 BoardDetail.boardId로 자동 매핑

7.3.6 식별, 비식별 관계의 장단점

데이터베이스 설계 관점 : 비식별 관계 > 식별 관계

  • 부모 테이블의 기본 키를 자식 테이블로 전파하면서 자식 테이블의 기본 키 컬럼이 점점 늘어남
ex) 부모 테이블 기본 키 컬럼 : 1개 
    -> 자식 테이블 기본 키 컬럼 : 2개 
    -> 손자 테이블 기본 키 컬럼 : 3개
따라서, 조인할 때 SQL 복잡해지고 기본 키 인덱스가 불필요하게 커짐
  • 2개 이상의 컬럼을 합해서 복합 기본키를 만들어야 하는 경우가 많음.
  • 식별 관계를 사용할 때 기본 키로 비즈니스 의미가 있는 자연 키 컬럼을 조합하는 경우가 많음.
  • 식별 관계는 부모 테이블의 기본 키를 자식 테이블의 키본키로 사용하여 비식별 관계보다 테이블 구조 유연 X

객체 관계 매핑의 관점 : 비식별 관계 > 식별 관계

  • 일대일 관계를 제외하고 식별 관계는 2개 이상의 컬럼을 묶은 복합 기본 키를 사용
    -> JPA에서 복합 키는 별도의 복합 키 클래스를 만들어서 사용
  • 비식별 관계의 기본 키는 주로 대리 키를 사용하는데 JPA는 @GenerateValue처럼 대리키를 생성하기 위한 방법 제공

식별 관계 > 비식별 관계

  • 기본 키 인덱스 활용하기 좋음
  • 상위 테이블들의 기본 키 컬럼을 자식, 손자 테이블들이 가지고 있어 특정 상황에 조인 없이 하위 테이블로 검색 가능

ORM 신규 프로젝트 진행시 추천하는 방법

비식별 관계를 사용하고, 기본 키는 Long 타입대리 키를 사용
+) 필수적 비식별 관계

  • 비식별 관계 : 식별자 컬럼이 하나여서 쉽게 매핑 가능
  • 대리 키 : 비즈니스와 아무 관련 X, JPA는 @GenerateValue를 통해 간편하게 대리 키 생성 가능
  • Long 타입 : 자바에서 Integer은 20억 정도가 끝 -> 데이터 많이 저장 시 문제 발생 -> 따라서 Long은 아주 커서 안전
  • 필수적 비식별 관계 : 선택적인 비식별 관계는 외부 조인 사용, 필수적 관계는 내부 조인 사용

얼마 전에 동아리에서 프로젝트 진행하면서 ERD를 설계하는데 식별/비식별 관계를 선택하는 부분이 있었다. 근데 이 책에서 그 내용이 나와 이 부분을 공부하면서 내가 설계한 테이블 조금 고쳐야될 것 같다고 생각했다..ㅎ

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


[자바 ORM 표준 JPA 프로그래밍] 값 타입


profile
Studying!!

0개의 댓글