ABOUT ME

-

Today
-
Yesterday
-
Total
-
  • JPA 고급매핑 (3)
    카테고리 없음 2023. 4. 20. 09:52

    복합키 식별 관계 매핑

    부모, 자식, 손자까지 계속 기본 키를 전달하는 식별관계가 있다고 치자 식별 관계에서 자식 테이블은 부모 테이블의 기본 키를 포함해서 복합 키를 구성해야 하므로 @IdClass 나 @EmbeddedId를 사용해서 식별자를 매핑해야 한다. (일대일 관계랑은 약간 다르다.)

    @IdClass

    @Entity
    @Data
    public class Parent {
      @Id
      @Column(name = "PARENT_ID")
      private String id;
    
      private String name;
    
    }
    
    @Entity
    @Data
    @IdClass(ChildId.class)
    public class Child {
      @Id
      @ManyToOne
      @JoinColumn(name = "PARENT_ID")
      private Parent parent;
    
      @Id
      @Column(name = "CHILD_ID")
      private String childId;
    
      private String name;
    }
    
    @Data
    public class ChildId implements Serializable {
    
      private String parent;
      private String childId;
    }
    
    @Entity
    @Data
    @IdClass(GrandChildId.class)
    public class CrandChild {
      @Id
      @ManyToOne
      @JoinColumns({
        @JoinColumn(name = "PARENT_ID"),
        @JoinColumn(name = "CHILD_ID"),
      })
      private Child child;
    
      @Id
      @Column(name = "GRANDCHILD_ID")
      private String id;
    
      private String name;
    }
    
    @Data
    public class GrandChildId implements Serializable{
      private ChildId child;
      private String id;
    }
    
    
    식별 관계는 기본 키와 외래 키를 같이 매핑 해야 한다. 따라서 식별자 매핑인 @Id와 연관관계 매핑인 @ManyToOne을 같이 사용하면 된다.
    @Id
    @ManyToOne
    @JoinColumn(name = "PARENT_ID")
    private Parent parent;
    
    Child 엔티티의 Parent 필드를 보면 @Id로 기본 키를 매핑하면서 @ManyToOne과 @JoinColumn으로 외래 키를 같이 매핑한다.

    EmbeddedId와 식별 관계

    @Entity
    @Data
    public class Parent {
      @Id
      @Column(name = "PARENT_ID")
      private String id;
    
      private String name;
    
    }
    
    @Entity
    @Data
    public class Child {
    
      @EmbeddedId
      private ChildId id;
    
      @MapsId("parentId") //ChildId.parentId 매핑
      @ManyToOne
      @JoinColumn(name = "PARENT_ID")
      private Parent parent;
    
      private String name;
    }
    
    @Data
    @Embeddable
    public class ChildId implements Serializable {
    
      private String parentId; //@MapsId("parentId") 로 매핑
      private String childId;
    }
    
    @Entity
    @Data
    public class CrandChild {
    
      @EmbeddedId
      private GrandChildId id;
    
      @MapsId("childId") // GrandChildId.childId 매핑
      @ManyToOne
      @JoinColumns({
        @JoinColumn(name = "PARENT_ID"),
        @JoinColumn(name = "CHILD_ID"),
      })
      private Child child;
    
      private String name;
    }
    
    @Data
    @Embeddable
    public class GrandChildId implements Serializable{
      private ChildId childId; //@MapsId("childId") 로 매핑
    
      @Column(name = "GRANDCHILD_ID")
      private String id;
    }
    
    
    @EmbeddedId는 식별 관계로 사용할 연관관계의 속성에 @MapsId를 사용하면 된다. Child 엔티티 parent 필드를 보자
    @MapsId("parentId") //ChildId.parentId 매핑
    @ManyToOne
    @JoinColumn(name = "PARENT_ID")
    private Parent parent;
    
    @IdClass와 다른 점은 @Id 대신에 @MapsId를 사용한 점이다. @MapsId는 외래 키와 매핑한 연관관계를 기본 키에도 매핑하겠다는 뜻이다. @MapsId의 속성 값은 @EmbeddedId를 사용한 식별자 클래스의 기본 키 필드를 지정하면 된다. 여기서는 ChildId의 parentId 필드를 선택했다.

    비식별 관계로 구현

    @Data
    @Entity
    public class Parent {
      @Id
      @GeneratedValue
      @Column(name = "PARENT_ID")
      private Long id;
    
      private String name;
    }
    
    @Entity
    @Data
    public class Child {
    
      @Id
      @GeneratedValue
      @Column(name = "CHILD_ID")
      private Long id;
    
      private String name;
    
      @ManyToOne
      @JoinColumn(name = "PARENT_ID")
      private Parent parent;
    }
    
    @Data
    @Entity
    public class GrandChild {
    
      @Id
      @GeneratedValue
      @Column(name = "GRANDCHILD_ID")
      private Long id;
    
      private String name;
    
      @ManyToOne
      @JoinColumn(name = "CHILD_ID")
      private Child child;
    }
    
    
    식별 관계의 복합 키를 사용한 코드와 비교하면 매핑도 쉽고 코드도 단순하다. 그리고 복합 키가 없으므로 복합 키 클래스를 만들지 않아도 된다.

    일대일 식별 관계

    일대일 식별관계는 자식 테이블의 기본 키 값으로 부모테이블의 기본 키 값만 사용한다. 그래서 부모 테이블의 기본 키가 복합 키가 아니면 자식 테이블의 기본 키는 복합 키로 구성하지 않아도 된다.
    @Entity
    @Data
    public class Board {
    
      @Id
      @GeneratedValue
      @Column(name = "BOARD_ID")
      private Long id;
    
      private String title;
    
      @OneToOne(mappedBy = "board")
      private BoardDetail boardDetail;
    
    }
    
    @Entity
    @Data
    public class BoardDetail {
    
      @Id
      private Long boardId;
    
      @MapsId
      @OneToOne
      @JoinColumn(name = "BOARD_ID")
      private Board board;
    
      private String content;
    }
    
    BoardDetail처럼 식별자가 단순히 컬럼 하나면 @MapsId를 사용하고 속성 값은 비워두면 된다. 이때 @MapsId는 @Id를 사용해서 식별자로 지정한 BoardDetail.boardId와 매핑된다.
    private static void save(EntityManager entityManager){
      Board board = new Board();
      board.setTitle("제목");
      entityManager.persist(board);
    
      BoardDetail boardDetail = new BoardDetail();
      boardDetail.setContent("내용");
      boardDetail.setBoard(board);
      entityManager.persist(boardDetail);
    }
    
    위의 코드는 일대일 식별 관계를 저장 하는 코드이다.

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

    데이터베이스 설계 관점에서 보면 다음과 같은 이유로 식별 관계보다 비식별 관계를 선호한다. 1. 식별 관계는 부모 테이블의 기본 키를 자식 테이블로 전파하면서 자식 테이블의 기본 키 컬럼이 점점 늘어난다. 그러면 조인할 때 SQL이 복잡해지고 기본 키 인덱스가 불필요하게 커질 수 있다. 2. 식별 관계는 2개 이상의 컬럼을 합해서 복합 기본 키를 만들어야 하는 경우가 많다. 3. 식별 관계를 사용할 때 기본 키로 비지니스 의미가 있는 자연 키 컬럼을 조합하는 경우가 많다. 반면에 비식별관계의 기본 키는 비지니스와 전혀 관계없는 대리 키를 주로 사용한다. 언제든지 요구사항은 변한다. 식별 관걔의 자연 키 컬럼들이 자식에 손자까지 전파되면 변경하기 힘들다. 4. 식별 관계는 부모 테이블의 기본 키를 자식 테이블의 기본 키로 사용하므로 비식별 관계보다 테이블 구조가 유연하지 못하다. 이외에도 몇가지가 더 있다. 하지만 무조건 식별관계가 단점만 있는 것은 아니다. 기본 키 인덱스를 활용하기 좋고, 상위 테이블들의 기본 키 컬럼을 자식, 손자 테이블들이 가지고 있으므로 특정 상황에 조인 없이 하위 테이블만으로 검색을 완료 할 수 있다. 이상으로 식별 비식별 관계에 대해 알아봤다. 다음은 고급매핑 마지막으로 조인 테이블에 대해서 알아보자! 출처 : 자바 ORM 표준 JPA 프로그래밍 (김영한)

    댓글

Designed by Tistory.