Chapter7. 고급 매핑

김신영·2022년 11월 22일
0

JPA

목록 보기
5/14
post-thumbnail
post-custom-banner

상속 관계 매핑 (@Inheritance)

객체의 상속 구조와 데이터베이스의 슈퍼타입 서브타입 관계를 매핑하는 것

  • 객체지향
    - 상속 관계
  • 관계형 데이터베이스
    - Super-Type Sub-Type Relationship
    - @Inheritance(stragety = InheritanceType.SINGLE_TABLE)
    - @DiscriminatorColumn , @DiscriminatorValue

data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAacAAAB3CAMAAACQeH8xAAAAe1BMVEX////x8fHj4+NycnKAgIBhYWG/v7/8/PxSUlKVlZWjo6PU1NRdXV3T09OHh4f39/ecnJy0tLSrq6tHR0dsbGw8PDxYWFjd3d3CwsKOjo7Kysrs7OxQUFCqqqp5eXm3t7cAAAA2NjYuLi4jIyMbGxssLCw7OzseHh4QEBCR19+ZAAAOV0lEQVR4nO2dDZ+iLBeHj2gYmALahEJqs7O7z/39P+GDNpUa9mKzpTP+f7tlKg56yeFwQASYNWvWrFlDRd+TIfpQr874D1OkByVLxRfnY9ZlRWhQMlx+cT7+gUI6VOGrs36ub8xprQKLpLStbSlcvDrr5/q+nNjCt60WCqzrm9qwr8/Og/rGnFbWq01w6QGYs/Y1OHYe/szpierjVK7eURJt/J337n5Yd5k5PVO95Ulx9Zf8JxP4C0Vg22Xm9Ez1ckp5sPbXOoE3cCfOiXDO1wjEhpOVdYfpcoqV/iW9hPsFuECkbZfpcMo00tycQwbArckmwemqX9enqXDygxJj7EBM4tx+y02B06KyCoM0FU4qLtexyFOa8zzntkxPgdPKtHOrpm56tWHbbecunVdn/kx2u6d4RgvTvkBeYC1Ok+C0MXavChfzu+3fZDhhmscugiIMw8zqEk2BU+VHKFA0u5fTdPwIz1RPWENhPr1Jc8o0h8335cS0kb//siabCieiAqDfl9NVTYVTxDKWzJzGrJoTAhTbPaELmjk9U5Z4xI0Fa+b0TO05cQUBAkopR6AsJYtaUs6cnqm9H8G4kwaQxyILIbLshS3u7Mzpmdr7ESBT4/KtMS51UALlFGKuNCclESAJARu8mdMzdeIk0ziO8zgPwAXKJPJQXMXKwWOhgOI85Sg58VL0CfduKYuJcKIyYqlkJssxCrFhI3QkI6TMEgc3xXIq5QnhXqW/0v6N44uAdbX3I0oEpn6KGAtLgySDGHlqhVKzRICmGVKWMWBj5HRJm1dn4CEd/XLj5nmUktAs+MDAQb5ffVetK2btXpsap+WrM/CQLO2nrhHowTFzeqZqTimlPgeHcGFKjviMVcqD76Tto69nTs/UZ3niLKt+kDyrRhHUEQl/H5cwn9lkxoVd0rfgZJyHAFiBeBamsM49KCKFBM+AUw4K21LOnJ6pPScqDSdVFSmOA1OiAhUZB5AAQlFQODK2pZw5PVP7fsK0HjSVEkJKJMCDMCQ1J42oowBbn8yYOT1TNafqgmf735kxgVsemXaTQjk15jDOrBG/mdNzdRy/l+6/sLF1ndYS6umaWs6cnifm/X2rlGx//aq/zb96odbntuPvt/f344+/xczpeWKhiONY5G6yy+OuxF/RWZPvkkzsV4pw5vQ8+Y5GWi3WOOYadaTDHe6s1FlJkny/6Awe8fwSTZtTLWbOYWtZH0n3bNcFwO9hvTwv1jfgBO4qt7VlN7A+s22R3E7zKf5px8trbUL5ZlmdUsB5dyXbBYupTYvhBFjQ37RM5bSq1LacpMeO5e7/3PMeDQdgSqCYWCQuFyoMVBoTs5y+OkcDhZL+m6xv6oG1NeI3QqXLXdo+PS1267vHKo5A6erCxt5t7vhHFBjhN87Iuu2WOptYe1vr4wBjFrWMUDmpn6Fnjc2OSjqpjTZ6b95TcVJ1r7Fi/Zo8DZVnf2D1oAtlLbKNvRyTyuTQMZ0dI5FOcsi1/DUl47e4Us9cmhqHXEb8akXeaRm97ZsS+8L0qeVU6lhgybV76uIURjz7wrx8taL2XcSXTqMw7XXtJh2LUHJ12NrlqaaovcNjDIq7WdObaNM93e0kTF+4vB6fuzIlWOxd3v4y6bMomLPxzvrL/F9Pys4jErd4PNembivP4n/j0Nkj3rmxHfqtG1xRY7bce2U3ZfHqFHvpKP3boFPO9WfNRJPO87l3P0T5bK1vi6VenwpRjXC2RHDbOOixItYdV+I8fDkq+dsb5wy9AUI4wjh00vyhkyaM+K3J0B9h5k/S3eLfq1sKSzC6jh3dNHu049U626bHPrq8NyQvBF47usmoSVsX4yulTgXI2Zwb+HJ7uk2L8T5Rg++oUW7bFY2sOlbvm0+tdsnisJwcFhbJ7rj9z2g58XvaPDcivdQ18lL5jRNoxCrF+Pugirs8nFuLnh4pKNaAMylOm/t6Ym82kc7bKA3IRDk5VwOvHd1elbGbfchnapqcbgi8dnSHyzFKUJPkpO5v1N0TbPD7hsO8UFPklF/sYbfrvqDQ+PoJJsgpGtL9emfwbjm24SHT4zSs8/LeIOtqZAP7psaJJcPu9LuD4SMbgTkxTnro1Mj39y6Na7jpSDixZHGT3lfdNdtjRC7cXkj4dumop77c6HT89cdNOdo+J37hj4OTtHXKGgKMXWvLFMcdcoul8o8flfrK4nGGZksvDmskYhYmxWM+vB/epKDZFGlwikuf3aSHMnmStX9/F0Mc/7mSsji40D633FsLDyAhx189xzgaU3Y+amRX/Dk66dQSUrS/quhmpRtOblLjJmxwCta3Kfmi7l4bJ7nYghBJTCFlSErBZWYpXMfrZOXkfoCz45ATXwDDApR1/sHl4bjOOacE8io9g5j4cRmc/Y3isZdQDnmR6oCu2/CLxvzaOBVorYV4V57YOGXOPZrY4hCXOa29IPcoz/Bio2n+rhP5YelhusRpt90xHuGV8NJtuTifweBRTgNGtw/gpP4hp93qF8HiDQJvwXDMVZC1hwvsdYVTUCwUXWn4T2Vv8Be/r23Bu8vlKSwWGj5cCX/E7jxO8eM5lRH4/4n4o3TLolzHRIWR//c85WVOKyeJFKFZuYGdBx8oQe+Wv36J0++0IDQqV6LAW8HPx9z/eE7KVO4qQCmNwclKJLUTgIXEZT9C+VJrWdVPEGrA99dPvogxVHUTCMIQcs6CIT+ME7m+j10NToMjCJt+TlflPZ/TgKFFX8bp92ZZa7Osh2V8Li8/1zbUWbP578Tp3SReVaM9lovVamV+JMvl4VhtJe2f70dO1YbVYrWpjlR91sc4aHVKfzzo5veDfvnEOB3KkzYNS/Y574YxfKjrnbGu3Tq+B8mvmhghJzLVkOU5laDMvlpaS1k75H6ye5WjgjOCKASUa8Fa7w84Pc0Xnqop77E44NQ4mfqJ0Q2tZvcSZVkYcIXk7DD3F6DPi4SgW5Gd/AhS109C4wwy00r3q9nBmKxWOnUkwfynDviVZ+2Llj/Q5gQkACKqqZsp0/wQxfCrGZth/4vBaajTC+qnF3MC+FMPT/FxfUVyRsFczjAFJ5BrpEGXDK2doFOTd/yIlEIZgMILjFAOPHZNSd3mkvNAZiRcxzoyDv4q1K0C1fYjJPEQN2s8yONYgifKMASqNnoduz4XBRRRYwLTn8fJcZ1Cc6ZS0zbV1QSiNCsAlWFKc104GRRO7BTNW7lW2y/n2Gepgyn1co5FPZ8lMZ8eLjPDnuXVHZCZy+60/JYWJ9+cUpiDIQM0oMiQrxJwkzICpTggU16BHFthP48T0lojwZSR8aELx9QNHjBCRA71NPE4C82n33m+rtN+coXw9u+rUX41L2JoOJHKDoYmKaI+92tOYatUtssTywh3gZg9KAuxFHWCKgOZ4UTqI16ze915sPoVk8b8WI3KmPUn0cnZPFsnNTLhNFaL7EKa/kNYOUFgaiZTP8Wx8IA41WVKA6FRTs21NZdagVtfqg6ntt3z/M+6h/EabWGKRg7ai5D574SEeZEMgk4td95+IvUloxoi3yMcPEIhkjkEEmemnIM+3Z42TmLr3aooOi0vGrmK1v1psv5N28bMBc1MNP/MFSWX+suP7dz9977M1H4EiWXomwpHASYSRHDmR7Q54VjEdd3BQmC9rphuO9PnnPYpA3aa+7ylxqlYOQ3rFUINUzHwfTVpg9PAJzjKSxOfHP3yff3sHJbPe4y6gVDPHjeqy8PZufac/IV4RCXdahywdp6snIY9fy4f54Qf5yQucQr/VE1To0X783NtQ501i49WecKmYjaNH0FyU0uVx3M9XGjru7a7nDjgqNDKyzBkCKp33Th18TrYunaJ/lmckLitt+xc4nBCNSfCSGwqj2qAX1RZT7PR11BNW17tppk9PNXmFJl60A8M5AKMwxmkODCcTR1PTJMMHAaqZdV+FidHBuG9r2WvX80eHCei23MShShyU5XlkXFAIDL1XlHSuPAj7MGbAPtT7V1O3JQ7zGPj4Rl/T0WmcUDTCJai8NdlwVjL4/xZnMAfrOMRak5AY50HZVlikQoIqKskMI0dAcp45jdyMv6hcVx0ZDx7L1Ce4YR59YYvXWaQSr/VgvthnB5XzSknUYxyph3P0cxc5eo6g0LYeOmlbLV7mupyyk0rDSPIdQZ6oajWxrhGTmUDieGEWmMNZk536tCvQevGTf2GDWPAIiCmeeyx0rSABGD72bc5mQZX5jqBl+Vg6rU4YJSpKnlEMnOIQPOW+3cHJ4lTXTus/lk0eb/9Kic/dOqaNqiMhG2H2ziFErTuG4L07zlRWVVZKhQykNVyyJE0i/v/9SeRtkpOJqc4rNnhc/c6RVAt8+AzebVChrR5ELm4mVMsmGPupQycUlvDONc5ucojGQcUC0da22g3cdIYs0j0Fdh/zildbbfHLqrNYWHb7ryqfx4+9tu2y+zQJHKI+VVv2LZSHddVH80Ore3StZyvnVOO6zK/yLPU2dh6ra5yCjE4tHoBGSHY3l9zEycUUb1w+wZG/nNOSPW/BvOi0uBgA5i88CpNu0LL4M0+u1diXVlkhh3rIydXOTHXIVFmSCnTSiS2C32b3XNNzU1fVZ6M1XeGqTFalN19DGYZZ2blJGksREydPOdoqN1zKmtFgKQ4f4BToREm5cs4jUf28qQI50RWgUfQw8qTcY0ojVhtQoPhdg9KTjP7KwBh5lR3fmoB9rJU6TonYRizSGaE0PgBTlWr83V2bzzq8SNMeYpScNYky6zX4jon5ubxp+PygL+3z83M6Z+2cy8/eTGBdu6INMcjpqGZ0zQ0c5qGZk7T0MxpGpo5TUPfd7zR91KZuEO0aYyQyVaDDtEcfLcZdAT3bSIv6/gKDQwIN0K6/sBDwJceYtasWbNmzZo1a9as6en/SIwaORhEoxgAAAAASUVORK5CYII=

슈퍼타입 서브타입 모델

1. 각각의 테이블로 변환 (JOINED 전략)

부모, 자식 테이블 모두 엔티티로 만들고, 자식 테이블이 부모 테이블의 기본키를 받아서 기본키+외래키로 설정
대신 부모 테이블에 DTYPE 컬럼이 필요하다.

  • @Inheritance(strategy = InheritanceType.JOINED)
  • DTYPE 컬럼 필요
    - @DiscriminatorColumn
    - @DiscriminatorValue
  • 기본적으로 자식 테이블은 부모 테이블의 ID 컬럼명을 그래도 사용
  • 자식 테이블의 기본 키 컬럼명을 변경하고 싶으면, @PrimaryKeyJoinColumn(name = "BOOK_ID")
@Entity  
@Table(name = "ART_ITEM")  
@Inheritance(strategy = InheritanceType.JOINED)
@DiscriminatorColumn(name = "ITEM_TYPE")  // default "DTYPE"
public abstract class ArtItem {  
    @Id @GeneratedValue  
    private Long id;  
    private String name;  
    private int price;  
}

@Entity  
@Table(name = "ALBUM")  
@DiscriminatorValue(value = "A")  
public class Album extends ArtItem {  
    private String artist;
}

@Entity  
@Table(name = "BOOK")  
@DiscriminatorValue(value = "B")  
public class Book extends ArtItem {  
    private String author;
}

@Entity  
@Table(name = "MOVIE")  
@DiscriminatorValue(value = "M")  
@PrimaryKeyJoinColumn(name = "BOOK_ID") // 기본 키 컬럼명 변경
public class Movie extends ArtItem {  
    private String director;  
    private String actor;
}    

장점

  • 테이블이 정규화된다.
  • 외래키 참조 무결성 제약조건을 활용할 수 있다.
  • 저장공간을 효율적으로 사용한다.

단점

  • 조회할 때 조인이 많이 사용되므로 성능이 저하될 수 있다.
  • 조회 쿼리가 복잡하다.
  • 데이터를 등록할 INSERT SQL을 두 번 실행한다.

2. 통합 테이블로 변환 (SINGLE_TABLE 전략)

  • 상속 관계 매핑의 기본 전략이다.
  • @Inheritance(strategy = InheritanceType.SINGLE_TABLE)
  • 자식 엔티티가 매핑한 컬럼은 모두 null 허용해야 한다.
  • @DiscriminatorColumn 을 무조건 설정해야 한다.
  • @DiscriminatorValue를 지정하지 않으면, 기본적으로 엔티티 이름으로 사용한다.

장점

  • JOIN이 필요 없으므로, 일반적으로 조회 성능이 빠르다.
  • 조회 쿼리가 단순하다.

단점

  • 자식 엔티티가 매핑한 컬럼은 모두 null을 허용해야 한다.
  • 단일 테이블에 모든 것을 저장하므로, 테이블이 커질 수 있다. 따라서 상황에 따라서는 조회 성능이 오히려 느려질 수 있다.

3. 서브타입 테이블로 변환 (TABLE_PER_CLASS 전략)

  • @Inheritance(strategy = InheritanceType.TABLE_PER_CLASS)
  • 자식 엔티티마다 테이블을 만든다.
  • @DiscriminatorColumn, @DiscriminatorValue 를 사용하지 않는다. (구분 칼럼을 사용하지 않는다.)
  • 일반적으로 추천하지 않는 전략

장점

  • 서브 타입을 구분해서 처리할 때 효과적이다.
  • not null 제약조건을 사용할 수 있다.

단점

  • 여러 자식 테이블을 함께 조회할 때 성능이 느리다. (SQL에 UNION을 사용해야 한다.)
  • 자식 테이블을 통합해서 쿼리하기 어렵다.

@MappedSuperclass

  • 테이블과 매핑하지 않고 자식 클래스에 엔티티의 매핑 정보를 상속하기 위해 사용한다.

  • @MappedSuperclass로 지정한 클래스는 엔티티가 아니므로, em.find() 나 JPQL에서 사용할 수 없다.

  • 이 클래스를 직접 생성해서 사용할 일은 거의 없으므로, 추상 클래스로 만드는것을 권장한다.

  • 부모로부터 물려받은 매핑 정보를 재정의하려면,
    - @AttributeOverrides
    - @AttributeOverride(name = "createdAt", column = @Column(name = "insertAt")

@MappedSuperclass
@EntityListeners(value = AuditingEntityListener.class)
@Getter
public abstract class BaseTimeEntity {
  @Column(updatable = false)
  @CreatedDate
  protected LocalDateTime createdAt;

  @LastModifiedDate
  protected LocalDateTime updatedAt;
}

@Entity
@Table(name = "MEMBER_INFO")
@AttributeOverrides({
	@AttributeOverride(name = "createdAt", column = @Column(name = "insertAt")),
	@AttributeOverride(name = "updatedAt", column = @Column(name = "updateAt"))
})
public class Member extends BaseTimeEntity {
	// ...
}

@Entity 는 @Entity이거나 @MappedSuperClass로 지정한 클래스만 상속받을 수 있다.

복합 키와 식별 관계 매핑

식별관계

  • 부모 테이블의 기본 키를 내려 받아서, 자식 테이블의 기본 키 + 외래 키로 사용하는 관계이다.

https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FUcYEB%2FbtrcxIl3q3e%2FK2ho5ldNfB7bLHY5nwogf1%2Fimg.png

비식별 관계

  • 부모 테이블의 기본 키를 받아서, 자식 테이블의 외래 키로만 사용하는 관계이다.

필수적 비식별 관계 (Mandatory)

  • 외래 키에 NULL을 허용하지 않는다.

선택적 비식별 관계 (Optional)

  • 외래 키에 NULL을 허용한다.

https://www.notion.so/image/https%3A%2F%2Fs3-us-west-2.amazonaws.com%2Fsecure.notion-static.com%2F87a8c7ec-91dd-4559-a713-d00008afe147%2FUntitled.png?table=block&id=2335a799-d40a-4a4e-bb0f-5e43a44ec579&spaceId=b453bd85-cb15-44b5-bf2e-580aeda8074e&width=2000&userId=80352c12-65a4-4562-9a36-2179ed0dfffb&cache=v2

복합 키

  • JPA에서 식별자(@Id)를 둘 이상 사용하려면 별도의 식별자 클래스를 만들어야 한다.

  • JPA는 영속성 컨텍스트에 엔티티를 보관할 때 엔티티의 식별자를 키로 사용한다.
    - 식별자를 구분하기 위해 equals, hashCode를 사용해서 동등성 비교를 한다.

  • JPA는 복합 키를 지원하기 위해 2가지 방법을 지원한다.
    - @IdClass
    - @EmbeddedId

  • 복합 키에는 @GeneratedValue 를 사용할 수 없다.

@IdClass

  • IdClass로 선언한 클래스 필수 조건
    1. Serializable 인터페이스 구현
    2. equals, hashCode 구현
    3. 기본 생성자
@Entity  
@Table(name = "PARENT")  
@IdClass(ParentId.class)  
public class Parent {  
    @Id  
    // @Column(name = "ID1")
    private Long id1;  // ParentId.id1 과 연결  
    @Id
    // @Column(name = "ID2")  
    private Long id2;  // ParentId.id2 와 연결
  
    private String name;
}

@EqualsAndHashCode  
public class ParentId implements Serializable {  

    private Long id1;  
    
    private Long id2;  
}
  • 데이터 저장시에 IdClass로 선언한 클래스를 직접 만들어서 세팅할 필요 없다.
  • JPA 내부에서 알아서 IdClass로 선언한 객체를 생성해서 식별자로 관리한다.
  • EntityManager를 통해 엔티티를 조회할 때, IdClass로 선언한 클래스를 활용해야한다.
ParentId parentId = ParentId.builder()  
    .id1(1L)  
    .id2(1L)  
    .build();  
  
Parent findParent = em.find(Parent.class, parentId);  // ParentId 클래스를 통해 조회

System.out.println("findParent = " + findParent);

복합 키를 외래 키로 매핑 설정

  • @JoinColumnname 속성과 referencedColumnName 속성 값이 같으면, referencedColumnName 은 생략해도 된다.
@Entity  
@Table(name = "CHILD")  
public class Child {  
    @Id  
    @GeneratedValue(strategy = GenerationType.IDENTITY)  
    private Long id;  
  
    @ManyToOne  
    @JoinColumns({  
        @JoinColumn(name = "PARENT_ID1", referencedColumnName = "ID1"),  
        @JoinColumn(name = "PARENT_ID2", referencedColumnName = "ID2"),  
    })  
    private Parent parent;  
  
    private String name;

@EmbeddedId

  • EmbeddedId를 설정한 클래스 필수 조건
    1. @Embeddable 어노테이션을 붙어주어야 한다.
    2. Serializable 인터페이스 구현
    3. equals, hashCode 구현
    4. 기본 생성자

  • EmbeddedId의 경우, 데이터를 저장할 때 EmbeddedId 클래스 객체를 직접 생성해야한다.

@Entity  
@Table(name = "PARENT")  
public class Parent {  
    @EmbeddedId  
    private ParentId2 id;  
  
    private String name;  
  
    @OneToMany(mappedBy = "parent")  
    private List<Child2> child2List;
}

@Embeddable  
@EqualsAndHashCode  
public class ParentId implements Serializable {  
//    @Column(name = "ID1")  
    private Long id1;  
//    @Column(name = "ID2")  
    private Long id2;  
}

@IdClass와 식별 관계

@Entity 
@Table(name = "PARENT")  
public class Parent {  
    @Id  
    @GeneratedValue(strategy = GenerationType.IDENTITY)  
    private Long id;  
  
    private String name;
}

@Entity
@Table(name = "CHILD")  
@IdClass(ChildId.class)  
public class Child {  
    @Id  
    private Long id;  
  
    @Id  
    @ManyToOne    
    @JoinColumn(name = "PARENT_ID")  
    private Parent parent;  
  
    private String name;
}

@EqualsAndHashCode
@NoArgsConstructor
public class ChildId implements Serializable {  
      
    private Long id;            // Child.id 매핑  
    
    private Long parent;        // Child.parent 매핑  
}

@Entity
@Table(name = "GRAND_CHILD")
@IdClass(GrandChildId.class)  
public class GrandChild {  
    @Id  
    private Long id;  
  
    @Id  
    @ManyToOne    
    @JoinColumns({  
        @JoinColumn(name = "CHILD_ID", referencedColumnName = "ID"),  
        @JoinColumn(name = "PARENT_ID", referencedColumnName = "PARENT_ID")  
    })  
    private Child child;  
  
    private String name;
}

@EqualsAndHashCode  
@NoArgsConstructor  
public class GrandChildId implements Serializable {  

    private Long id;        // GrandChild.id 매핑  
    
    private ChildId child;  // GrandChild.child 매핑  
}

@EmbeddedId 와 식별 관계

@MapsId

  • 외래키와 매핑한 연관관계를 기본 키에도 매핑하겠다는 뜻
  • @MapsId 의 속성 값은 @EmbeddedId 를 사용한 식별자 클래스의 기본 키 필드를 지정하면 된다.
@Entity 
@Table(name = "PARENT")  
@Getter  
@Setter  
@AllArgsConstructor  
@NoArgsConstructor  
@Builder  
public class Parent {  
    @Id  
    @GeneratedValue(strategy = GenerationType.IDENTITY)  
    private Long id;  
  
    private String name;
}

@Entity 
@Table(name = "CHILD")  
public class Child {  
    @EmbeddedId  
    private ChildId id;  
  
    @MapsId("parentId")  
    @ManyToOne  
    @JoinColumn(name = "PARENT_ID")  
    private Parent parent;  
  
    private String name;
}

@Embeddable  
@NoArgsConstructor  
public class ChildId implements Serializable {  
	
	// Child.parentId 로 매핑 -> @MapsId("parentId")로 매핑
    private Long parentId;

	// Child.id 로 매핑
    private Long id;
}

@Entity
@Table(name = "GRAND_CHILD")  
public class GrandChild {  
    @EmbeddedId  
    private GrandChildId id;  
  
    @MapsId("childId")  
    @ManyToOne  
    @JoinColumns({  
        @JoinColumn(name = "PARENT_ID", referencedColumnName = "PARENT_ID"),  
        @JoinColumn(name = "CHILD_ID", referencedColumnName = "ID"),  
    })  
    private Child child;  
  
    private String name;
}

@Embeddable  
@NoArgsConstructor  
public class GrandChildId implements Serializable {  

	// GrandChild.id 로 매핑
    private Long id;

	// GrandChild.childId 로 매핑 -> @MapsId("childId")로 매핑
    private ChildId childId;
}

비식별 관계로 구현

@Entity 
@Table(name = "PARENT")  
public class Parent {  
    @Id  
    @GeneratedValue(strategy = GenerationType.IDENTITY)  
    private Long id;  
  
    private String name;
}

@Entity
@Table(name = "CHILD")  
public class Child {  
    @Id  
    @GeneratedValue(strategy = GenerationType.IDENTITY)  
    private Long id;  
  
    @ManyToOne  
    @JoinColumn(name = "PARENT_ID")  
    private Parent parent;  
  
    private String name;
}

@Entity  
@Table(name = "GRAND_CHILD")  
public class GrandChild {  
    @Id  
    @GeneratedValue(strategy = GenerationType.IDENTITY)  
    private Long id;  
  
    @ManyToOne  
    @JoinColumn(name = "CHILD_ID")  
    private Child child;  
  
    private String name;
}

비식별 관계를 추천한다.

profile
Hello velog!
post-custom-banner

0개의 댓글