올해 초 복합키, 외래키 사용이 많은 테이블을 JPA Entity로 구현했어야 했는데, JPA 사용이 처음이였어서 익숙하지 않아 복잡하게 느껴졌었다. 나같은 사람을 위해 정리해 본다!
Entity에 복합키를 통한 식별관계를 매핑하는 방법은 @IdClass, @EmbededId 두가지가 있는데 본인은 @IdClass를 사용했다.
@EmbededId는 @IdClass 방식 보다 좀더 객체지향 방식이라고 한다.
하지만 특정 객체를 사용하기 위해서 객체 그래프를 깊게 탐색해야하는 경우가 있고, 깊이 감춰져 있어서 명시적으로 보이지 않는다고..
예를 들어 grandChild Entity에서 parent_id를 구하기 위해선 아래와 같이 탐색해야 한다.
grandChild.getGId().getCId().getPId().getParentId();
IdClass들이 중첩구조로 겹겹이 쌓여지는 것을 볼 수 있다.
@IdClass 방식을 사용할 경우는 아래와 같다.
grandChid.getChild().getParent().getParentId();
@IdClass 방식과 @EmbededId 방식은 depth가 하나밖에 차이나지 않지만 @IdClass 방식은 IdClass가 중첩구조로 쌓여지는게 아니라 Entity가 중첩구조로 쌓여져서 명시적인 면에서 더 나아보이는 듯?!
(단순한 하나의 복합키만 존재한다고 하면 @EmbededId 를 사용하고, 복합키를 통한 식별관계 매핑이 여기저기 존재한다면 @IdClass를 이용하라고 권한다고 하더라)
아래는 @IdClass를 사용하여 Entity를 어떻게 구현했는지 보여주고자 했다.
Parent
- Parent Entity
@ToString
@Entity
@Table(name = "PARENT")
public class Parent {
@Id
@Column(name = "PARENT_ID", columnDefinition ="VARCHAR(36)", nullable = false)
private String parentId;
@Column(name = "PARENT_NAME", columnDefinition ="VARCHAR(32)", nullable = false)
private String parentName;
}
parent는 특별히 추가로 세팅해주는것이 없다
Child
- Child Entity
@ToString
@Entity
@IdClass(ChildId.class)
@Table(name = "CHILD")
public class Child {
@Id
@ManyToOne(cascade = CascadeType.PERSIST)
@JoinColumn(name="PARENT_ID", columnDefinition ="VARCHAR(36)", nullable = false)
public Parent parent;
@Id
@Column(name = "CHILD_ID", columnDefinition ="VARCHAR(36)", nullable = false)
private String childId;
@Column(name = "CHILD_NAME", columnDefinition ="VARCHAR(64)", nullable = false)
private String childName;
}
- ChildId.class
@NoArgsConstructor
@AllArgsConstructor
@EqualsAndHashCode
@Getter
@Setter
public class ChildId implements Serializable {
private String parent;
private String childId;
}
GrandChild
- GrandChild Entity
@Entity
@ToString
@Table(name = "GRANDCHILD")
@IdClass(GrandChildId.class)
public class GrandChild {
@Id
@Column(name = "GRAND_CHILD_ID", columnDefinition ="VARCHAR(36)")
private String grandChildId;
@Id
@ManyToOne
@JoinColumns({
@JoinColumn(name = "PARENT_ID", columnDefinition ="VARCHAR(36)", referencedColumnName = "PARENT_ID"),
@JoinColumn(name = "CHILD_ID", columnDefinition ="VARCHAR(36)", referencedColumnName = "CHILD_ID")
})
private Child child;
@Column(name = "GRAND_CHILD_NAME", columnDefinition ="VARCHAR(64)", nullable = false)
private String grandChildName;
}
- GrandChildId.class
@NoArgsConstructor
@AllArgsConstructor
@EqualsAndHashCode
@Getter
@Setter
public class GrandChildId implements Serializable {
private ChildId child;
private String grandChildId;
}
참고한 사이트
Legacy DB의 JPA Entity Mapping (복합키 매핑 편) | 우아한형제들 기술블로그
{{item.name}} 안녕하세요. 우아한형제들에서 배달의민족 서비스의 광고시스템을 개발하고 있습니다. 시스템을 점진적으로 Spring Boot / JPA 기반으로 이관하면서 경험했던 내용을 공유하고자 합니다.
techblog.woowahan.com
'개발 > JPA' 카테고리의 다른 글
[JPA] Specification을 이용하여 쿼리 조건 처리하기 - 외래키 (2) | 2022.01.07 |
---|---|
[JPA] @OnDelete VS cascade = CascadeType.REMOVE (1) | 2021.12.13 |
[JPA] 데이터를 insert 하기 전에 select하는 이유 (0) | 2021.12.02 |
[JPA] @OneToMany - 자식 테이블(관계 Entity)의 데이터를 상황에 따라 가져오기 (0) | 2021.11.26 |
댓글