7.3.1 식별관계 vs 비식별관계
- 식별관계
식별관계는 부모 테이블의 기본키를 내려받아서 자식테이블의 기본키 + 외래키로 사용하는 관계다.
- 비식별관계
- 비식별관계는 부모테이블의 기본키를 받아서 자식테이블의 외래키로만 사용하는 관계이다.
- 필수적 비식별 관계 : 외래키에 NULL을 허용하지 않는다. 연관관계를 필수로 맺어야한다.
- 선택적 비식별 관계 : 외래키에 NULL을 허용한다. 연관관계를 맺을지 선택할 수 있다.
7.3.2 복합키 : 비식별 관계 매핑
JPA는 영속성 컨텍스트에 엔티티를 보관할 때 엔티티의 식별자를 키로 사용한다. 그리고 식별자를 구분하기 위해 equals와 hashcode를 사용해서 동등성 비교를 한다. 때문에 식별자 필드가 두개 이상일 경우에는 별도의 식별자 클래스를 만들고 그곳에 equals와 hashcode를 구현한다.
@IdClass
- 부모 클래스
@Entity
@IdClass(Parent)
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 implement Serializable {
private String id1; //Parent.id1 매핑
private String id2; //Parent.id2 매핑
public ParentId(){}
public ParentId(String id1, String id2){
this.id1 = id1;
this.id2 = id2;
}
@Override
public boolean equals(Object 0){}
@Override
public int hashcode(){}
}
@IdClass를 사용할 때 식별자 클래스는 다음 조건을 만족해야한다.
- 식별자 클래스의 속성명과 엔티티에서 사용하는 식별자의 속성면이 같아야 한다. 예제의 Parent.id1과 Parent.id2, 그리고 Parent.id2와 ParentId.id2가 같다.
- Serializable 인터페이스를 구현해야한다.
- equals, hashcode를 구현해야 한다.
- 기본생성자가 있어야한다.
- 식별자 클래스는 public이어야 한다.
- 식별자 클래스를 이용하여 조회
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);
- 저장코드를 보면 식별자 클래스인 parentId가 보이지 않는데, em.persist()를 호출하면 영속성 컨텍스트에 엔티티를 등록하기 직전에 내부에서 Parent.id1, Parent.id2 값을 사용해서 식별자 클래스인 ParentId를 생성하고 영속성 컨텍스트의 키로 사용한다.
- 자식클래스
@Entity
public class Child {
@Id
private String id;
@ManyToOne
@JoinColumns({
@JoinColumn(name = "parent_id1", referencedColumnName = "parent_id1"),
@JoinColumn(name = "parent_id2", referencedColumnName = "parent_id2")
})
private Parent parent;
}
부모 테이블의 기본 키 컬럼이 복합키이므로 자식테이블의 외래키도 복합키다. 따라서 외래 키 매핑시 여러 컬럼을 매핑해야 하크로 @JoinColumns 어노테이션을 사용하고 각각의 외래 키 컬럼을 @JoinColumn으로 매핑한다.
@JoinColumn의 name속성과 referencedColumnName 속성의 값이 같으면 referencedColumnName은 생략이 가능하다.
@EmbeddedId
@IdClass가 데이터베이스에 맞춘 방법이라면 @EmbeddedId는 좀 더 객체지향적인 방법이다.
@Entity
public class Parent {
@EmbeddedId
private ParentId id;
private String name;
}
@IdClass와는 다르게 @EmbeddedId를 적용한 식별자 클래스는 식별자 클래스에 기본 키를 직접 매핑한다.
@Entity
public class ParentId implements Serializable {
@Column(name = "PARENT_ID1")
private String id1;
@Column(name = "PARENT_ID2")
private String id2;
//equals and hashcode 구현
}
@EmbeddedId를 적용한 식별자 클래스는 다음 조건을 만족해야 한다.
- @EmbeddedId 어노테이션을 붙여줘야한다.
- 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);
복합 키에는 @GenerateValue를 사용할 수 없다. 복합 키를 구성하는 여러 컬럼 중 하나에도 사용할 수 없다.
'JPA' 카테고리의 다른 글
08 프록시 객체 (0) | 2021.01.15 |
---|---|
6.1 다대일 (0) | 2021.01.11 |
05 연관관계 매핑 (0) | 2021.01.10 |
기본키 매핑방식 (0) | 2021.01.10 |
hibernate.ejb.naming_strategy (0) | 2021.01.10 |