식별 관계와 복합 키 매핑

식별 관계

부모의 PK를 받아 FK이자 PK로 사용합니다.

단점이 너무 많아요오….

비식별 관계

부모의 PK가 FK의 역할만 합니다.

자손 테이블은 PK에 비즈니스와 관련 없는 대리키를 사용하는 경우가 대부분입니다.

  1. 필수 : 자식의 FK에 NULL이 올 수 없습니다. 부모가 무조건 있어야 합니다.
  2. 선택 : 자식의 FK에 NULL이 와도 됩니다. 부모가 있어도 되고 없어도 됩니다.

복합 키 : 비식별 관계

단일 키일때는 보통 자바의 기본 타입을 사용하지만 복합키일 땐 별도의 식별자 클래스를 만들고 Serializable 을 구현해야 합니다.

왜냐하면 JPA는 영속성 컨텍스트에 엔티티를 보관할 때 엔티티의 식별자를 키로 사용하는데 이 식별자를 구분하기 위해 equalshashCode 를 사용해 동등성 비교를 합니다.

Untitled

@IdClass를 사용한 비식별 복합 키

@Entity
@IdClass(ParentId.class)
public class Parent {
    @Id
    @Column(name = "PARENT_ID1")
    private String id1;
    @Id
    @Column(name = "PARENT_ID2")
    private String id2;
    private String name;
}

public class ParentId implements Serializable {
    private String id1;
    private String id2;

    public ParentId() {
    }
		//getter&setter
		//equals&hashCode
}
@Entity
public class Child{
    @Id @GeneratedValue
    @Column(name = "CHILD_ID")
    private Long id;

    @ManyToOne
    @JoinColumns({
            @JoinColumn(name = "PARENT_ID1", referencedColumnName = "PARENT_ID1"),
            @JoinColumn(name = "PARENT_ID2", referencedColumnName = "PARENT_ID2")
    })
    private Parent parent;

    private String name;
}

Untitled

@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;

    public ParentId() {
    }
		//getter&setter
		//equals&hashCode
}
Parent parent = new Parent();
ParentId parentId = new ParentId();
parentId.setId1("myId1");
parentId.setId2("myId2");
parent.setId(parentId);

복합 키 : 식별 관계

Untitled

@IdClass를 이용한 식별 복합 키

@Entity
public class Parent {
    ***@Id @Column(name = "PARENT_ID")
    private String id;***
    private String name;
}

@Entity
@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;
}

@Entity
@IdClass(GrandChildId.class)
public class GrandChild {
    ***@Id
    @ManyToOne
    @JoinColumns({
        @JoinColumn(name = "PARENT_ID"),
        @JoinColumn(name = "CHILD_ID")
    })
    private Child child;***

    @Id @Column(name = "GRANDCHILD_ID")
    private String grandChildId;

    private String name;
}
public class ChildId implements Serializable {
    private String parent;
    private String childId;
}

public class GrandChildId implements Serializable {
    ***private ChildId child;***
    private String grandChildId;
}
// 부모 생성
Parent parent = new Parent();
parent.setName("parentName1");
em.persist(parent);

// 자식 생성
Child child = new Child();
child.setName("childName1");
child.setParent(parent);
em.persist(child);

// 손주 생성
GrandChild grandChild = new GrandChild();
grandChild.setName("grandChildName1");
grandChild.setChild(child);
em.persist(grandChild);
tx.commit();
em.clear();

// 부모 조회
Parent findParent = em.find(Parent.class, parent.getId());

// 자식 조회
ChildId childId = new ChildId();
childId.setParent(findParent.getId());
childId.setChildId(child.getChildId());
Child findChild = em.find(Child.class, childId);

// 손주 조회
GrandChildId grandChildId = new GrandChildId();
grandChildId.setChild(childId);
grandChildId.setGrandChildId(grandChild.getGrandChildId());
GrandChild findGrandChild = em.find(GrandChild.class, grandChildId);

Untitled

@EmbeddedId를 이용한 식별 복합 키

@Entity
public class Parent {
    @Id
    @Column(name = "PARENT_ID")
    private String id;
    private String name;
}

@Entity
public class Child {
    @EmbeddedId
    private ChildId id;
    **@MapsId("parentId")
    @ManyToOne
    @JoinColumn(name = "PARENT_ID")
    private Parent parent; //ChildId 클래스의 parentId에 매핑**
    private String name;
}

@Entity
public class GrandChild {
    @EmbeddedId
    private GrandChildId id;

    **@MapsId("childId")
    @ManyToOne
    @JoinColumns({
        @JoinColumn(name = "PARENT_ID"),
        @JoinColumn(name = "CHILD_ID")
    })
    private Child child; //GrandChildId 클래스의 childId에 매핑**

    private String name;
}
@Embeddable
public class ChildId implements Serializable {
    @Column(name = "CHILD_ID")
    private String childId;
    **private String parentId; //@MapsId로 매핑된 키**
		//noArgsConstructor
		//getter&setter
		//equals&hashCode
}

@Embeddable
public class GrandChildId implements Serializable {
    @Column(name = "GRANDCHILD_ID")
    private String grandChildId;
    **private ChildId childId; //@MapsId로 매핑된 키**
		//noArgsConstructor
		//getter&setter
		//equals&hashCode
}
// 부모 생성
Parent parent = new Parent();
parent.setId("parentId");
parent.setName("parent");
em.persist(parent);

// 자식 생성
Child child = new Child();
child.setId(new ChildId(parent.getId(), "childId"));
child.setName("child");
child.setParent(parent);
em.persist(child);

// 손주 생성
GrandChild grandChild = new GrandChild();
grandChild.setId(new GrandChildId(child.getId(), "grandChildId"));
grandChild.setName("grandChild");
grandChild.setChild(child);
em.persist(grandChild);

tx.commit();
em.clear();

// 부모 조회
Parent findParent = em.find(Parent.class, parent.getId());
// 자식 조회
Child child1 = em.find(Child.class, child.getId());
// 손주 조회
GrandChild grandChild1 = em.find(GrandChild.class, grandChild.getId());

Untitled

단일 키 : 식별 관계

부모와 자손이 일대일 관계일때 부모의 PK가 자손의 PK가 되는 단일 키 식별관계를 만들 수 있습니다.

Untitled

@Entity
public class Board {
    @Id @GeneratedValue
    @Column(name = "BOARD_ID")
    private Long id;
    private String title;

    **@OneToOne(mappedBy = "board")
    private BoardDetail boardDetail;**

		//getter&setter
}

@Entity
public class BoardDetail {
    **@Id
    private Long boardId;

    *@MapsId*
    @OneToOne
    @JoinColumn(name = "BOARD_ID")
    private Board board;**

    private String content;
		
		//getter&setter
}
//게시글 등록
Board board = new Board();
board.setTitle("board1");
em.persist(board);

//게시글 작성
BoardDetail boardDetail = new BoardDetail();
boardDetail.setContent("board1 - content1");
boardDetail.setBoard(board);
em.persist(boardDetail);

tx.commit();
em.clear();

//게시글 찾기
Board findBoard = em.find(Board.class, board.getId());
//게시글 작성 내용 찾기
BoardDetail findBoardDetail = em.find(BoardDetail.class, ***board.getId()***);

Untitled