@Inheritance
)객체의 상속 구조와 데이터베이스의 슈퍼타입 서브타입 관계를 매핑하는 것
@Inheritance(stragety = InheritanceType.SINGLE_TABLE)
@DiscriminatorColumn
, @DiscriminatorValue
부모, 자식 테이블 모두 엔티티로 만들고, 자식 테이블이 부모 테이블의 기본키를 받아서 기본키+외래키로 설정
대신 부모 테이블에DTYPE
컬럼이 필요하다.
@Inheritance(strategy = InheritanceType.JOINED)
DTYPE
컬럼 필요
-@DiscriminatorColumn
-@DiscriminatorValue
@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;
}
@Inheritance(strategy = InheritanceType.SINGLE_TABLE)
@DiscriminatorColumn
을 무조건 설정해야 한다.@DiscriminatorValue
를 지정하지 않으면, 기본적으로 엔티티 이름으로 사용한다.@Inheritance(strategy = InheritanceType.TABLE_PER_CLASS)
@DiscriminatorColumn
, @DiscriminatorValue
를 사용하지 않는다. (구분 칼럼을 사용하지 않는다.)@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로 지정한 클래스만 상속받을 수 있다.
JPA에서 식별자(@Id)를 둘 이상 사용하려면 별도의 식별자 클래스를 만들어야 한다.
JPA는 영속성 컨텍스트에 엔티티를 보관할 때 엔티티의 식별자를 키로 사용한다.
- 식별자를 구분하기 위해 equals
, hashCode
를 사용해서 동등성 비교를 한다.
JPA는 복합 키를 지원하기 위해 2가지 방법을 지원한다.
- @IdClass
- @EmbeddedId
복합 키에는 @GeneratedValue
를 사용할 수 없다.
@IdClass
Serializable
인터페이스 구현equals
, hashCode
구현@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;
}
ParentId parentId = ParentId.builder()
.id1(1L)
.id2(1L)
.build();
Parent findParent = em.find(Parent.class, parentId); // ParentId 클래스를 통해 조회
System.out.println("findParent = " + findParent);
@JoinColumn
의 name
속성과 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;
}
@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 매핑
}
@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;
}