일 | 월 | 화 | 수 | 목 | 금 | 토 |
---|---|---|---|---|---|---|
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 |
- String
- MySQL시작하기
- SpringBoot
- 우분투에war배포
- Java
- springMVC
- K8S
- appleM1
- Lombok
- Seek_Keyset
- 스프링에러
- pagination
- minikube
- NullPointerException
- intellij
- restful api
- wappalyzer
- DB생성
- MySQL
- CloutNative
- spring
- 이클립스
- frontend
- Postman
- gradle
- MYSQL에러
- windows10
- offset
- SQL
- VUE
- Today
- Total
미운 오리 새끼의 우아한 개발자되기
[JPA] 고급 매핑 (3) 복합 키 본문
1. 식별 관계 vs. 비식별 관계
- 식별 관계
식별관계는 부모 테이블의 기본 키를 내려받아 자식 테이블의 기본 키 + 외래 키로 사용하는 관계.
- 비식별 관계
비식별 관계는 부모 테이블의 기본 키를 받아서 자식 테이블의 외래 키로만 사용하는 관계.
비식별 관계는 외래 키에 NULL 을 허용하는 지에 따라 필수적 비식별 관계와 선택적 비식별 관계로 나뉨.
- 필수적 비식별 관계(Mandatory): 외래 키에 NULL 허용 x. 연관관계가 필수적으로 맺어져야함.
- 선택적 비식별 관계(Optional): 외래 키에 NULL 을 허용. 연관관계를 맺을 지 말지 선택가능.
최근에는 비식별관계를 주로 사용하고, 꼭 필요한 곳에만 식별 관계를 사용하는 추세.
1.2. 복합 키: 비식별 관계 매핑
JPA 에서 식별자를 둘 이상 사용하기 위해서는 별도의 식별자 클래스를 만들어야함.
@Entity
public class Hello {
@Id
private String id;
@Id
private String id2; // 실행 시점에 매핑 예외 발생
}
JPA 는 영속성 컨텍스트에 엔티티를 보관할 때 엔티티의 식별자를 키로 사용하기 때문에 식별자를 구분하기 위해 equals 와 hashCode 를 사용해서 동등성 비교를 해야한다.
JPA 에서는 복합 키를 지원하기 위해 @IdClass 와 @EmbeddedId 이 두 가지 방법을 제공하는데
@IdClass 가 관계형 DB 에 가까운 방법ㅂ이고 @EmbeddedId 는 좀 더 객체지향에 가까운 방법이다.
@IdClass
@Entity
@IdClass(ParentId.class) // 복합키 클래스
public class Parent {
@Id
@Column(name = "PARENT_ID1")
private String id1; // ParentId.id1 과 연결
@Id
@Column(name = "PARENT_ID2")
private String id2; // ParentId.id2 와 연결
private String name;
...
}
public class ParentId implements Serialize {
private String id1; // Parent.id1 매핑
private Stirng id2; // Parent.id2 매핑
public ParentId(String id1, String id2) {
this.id1 = id1;
this.id2 = id2;
}
@Override
public boolean equals(Object c) { ... }
@Override
public int hashCode() { ... }
}
@IdClass 사용 시 만족해야할 조건
- 식별자 클래스의 속성명과 엔티티에서 사용하는 식별자의 속성명이 동일해야 함
- Serializable 인터페이스를 구현해야 함
- equals, hashCode 구현
- 기본 생성자 필요
- 식별자 클래스는 public
@Entity
public class Child {
@Id
private String id;
@ManyToOne
@JoinColumns({
@JoinColumn(name = "PARENT_ID1",
referenceColumnName = "PARENT_ID1"),
@JoinColumn(name = "PARENT_ID2",
referenceColumnName = "PARENT_ID2")
})
private Parent parent;
...
}
아래는 실제로 사용하는 예시 코드
// 복합 키를 사용하는 엔티티의 저장 예시코드
Parent parent = new Parent();
parent.setId1("myId1");
parent.setId2("myId2");
parent.setName("parentName");
em.persist(parent);
// 엔티티 조회
ParentId parentId = new ParentId("myId1", "myId2");
Parent parent = em.find(Parent.class, parentId);
@EmbeddedId
@IdClass 에 비해 @EmbeddedId 는 더 객체지향적인 방법이다.
@Entity
public class Parent {
@EmbeddedId
private ParentId id;
private String name;
}
@Embeddable
public class ParentId implements Serializable {
@Column(name = "PARENT_ID1")
private String id1;
@Column(name = "PARENT_ID2")
private String id2;
// equals and hashCode 구현
...
}
@EmbeddedId 를 적용하는 식별자 클래스의 조건
- 식별자 클래스에 기본 키를 직접 매핑 해야한다. (위의 ParentId 클래스 참고)
- @Embeddable 어노테이션
- Serializable 인터페이스 구현
- equals, hashCode 구현
- 기본생성자 필요
- 식별자 클래스는 public
// 엔티티 저장
Parent parent = new Parent();
ParentId parentId = new ParentId("myId1", "myId2");
parent.setId(parentId);
parent.setName("parentName");
em.persist(parent);
// 엔티티 조회
ParentId parentId = new ParentId("myId1", "myId2");
Parent parent = em.find(Parent.class, parentId);
복합 키와 equals(), hashCode()
복합 키는 equals() 와 hashCode() 를 필수로 구현해야함.
Java 에서 equals() 를 오버라이딩하지 않는 경우는 인스턴스의 참조 값 비교의 == (동일성)비교 만 하기 때문.
영속성 컨텍스트는 엔티티의 식별자를 키로 사용해서 엔티티를 관리하는데 이때 식별자를 비교할 때, equals() 와 hashCode() 를 사용하기 때문에 이 두 메서드가 오버라이딩 되지 않으면 예상과 다른 결과값이 나오거나 엔티티를 찾을 수 없는 등의 심각한 문제가 발생함.
@IdClass vs. EmbeddedId
각각의 장단점을 고려하여 취향에 맞는 걸로 일관성있게 사용하면 됨.
참고: 복합 키에는 @GeneratedValue 를 사용할 수 없음. 복합 키를 구성하는 컬럼 중 하나에도 사용 할 수 없음
Reference : 자바 ORM 표준 JPA 프로그래밍 (김영한 저)
'Spring & Spring Boot' 카테고리의 다른 글
[JPA] 영속성 관리 (1) 엔티티 매니저 팩토리와 엔티티 매니저 (0) | 2023.05.23 |
---|---|
[JPA] 고급 매핑 (2) @MappedSuperclass (0) | 2023.05.09 |