본문 바로가기
개발/JPA

[JPA] 복합키, 외래키 Entity 설정하기(@IdClass를 사용하여 식별관계 매핑)

by zuzuu 2021. 12. 23.
반응형

올해 초 복합키, 외래키 사용이 많은 테이블을 JPA Entity로 구현했어야 했는데, JPA 사용이 처음이였어서 익숙하지 않아 복잡하게 느껴졌었다. 나같은 사람을 위해 정리해 본다!

복합키를 pk로 사용한 테이블의 pk를 외래키로 참조할 경우 해당 복합키 모두 참조해야만 한다.

 

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

 

728x90
반응형

댓글