JPA

실전 예제 4 - 상속관계 매핑

방구석 대학생 2020. 10. 11. 18:13

"인프런 - 자바 ORM 표준 JPA 프로그래밍 강의를 듣고 작성한 글 입니다."

www.inflearn.com/course/ORM-JPA-Basic#

 

자바 ORM 표준 JPA 프로그래밍 - 기본편 - 인프런

JPA를 처음 접하거나, 실무에서 JPA를 사용하지만 기본 이론이 부족하신 분들이 JPA의 기본 이론을 탄탄하게 학습해서 초보자도 실무에서 자신있게 JPA를 사용할 수 있습니다. 초급 웹 개발 프로그

www.inflearn.com

 

앞의 글 들을 통해 배웠던 내용을 통해 실전 예제 프로젝트에서 상속 관계를 매핑해보자.

- 위의 논리 모델을 보면 상품(Item) 의 종류로 음반, 도서, 영화가 있음을 알 수 있다.(이후에 더 확장될 수 있음)

- 모든 데이터는 등록일과 수정일이 필수로 존재해야 한다.(MappedSuperclass)

- 이번 예제에서는 상속 관계를 단일 테이블 전략으로 매핑해준다.

객체간 상속관계 설계 논리 모델

 

우선 공통 필드인 등록일, 수정일 필드를 생성하기 위해 MappedSuperclass 를 활용하는 BaseEntity 클래스를 생성하여 아래와 같이 코드를 작성해준다.

- BaseEntity.java

@MappedSuperclass
public class BaseEntity {

	private String createdBy;
	private LocalDateTime createdDate;
	private String lastModifiedBy;
	private LocalDateTime lastModifiedDate;
    
	// Getter, Setter
}

 

이후 Main 클래스슈퍼 타입 클래스에 서브 타입 클래스로 매핑될 도메인 들을 제외한 모든 도메인 클래스에 위의 

BaseEntity 클래스를 상속받아 준다.

서브 타입 클래스로 매핑될 도메인의 경우 슈퍼 타입 클래스만 BaseEntity 클래스를 상속받아 주면 자동으로 해당되는 공통 필드를 상속받는다.

- Member.java

@Entity
public class Member extends BaseEntity {
 ......
}

- Order.java

@Entity
@Table(name = "ORDERS")
public class Order extends BaseEntity {
 ......
}

- OrderItem.java

@Entity
public class OrderItem extends BaseEntity {
 ......
}

- Delivery.java

@Entity
public class Delivery extends BaseEntity {
 ......
}

- Category.java

@Entity
public class Category extends BaseEntity {
 ......
}

 

Item 클래스의 경우 슈퍼 타입 클래스로서 상속관계를 매핑해야 하기 때문에 @Inheritance 어노테이션을 활용해주며,

Item 클래스 자체의 데이터가 들어갈 일이 없다고 가정하기 위해 abstract 키워드를 활용하여 Item 클래스를 추상 클래스로 만들어준다.

- Item.java

@Entity
@Inheritance(strategy = InheritanceType.SINGLE_TABLE)
//@DiscriminatorColumn 단일 테이블 전략을 사용하여 상속관계를 매핑할 경우, 해당 어노테이션은 없어도 상관없다.
public abstract class Item extends BaseEntity{
 // Item 클래스에만 따로 데이터를 저장할 일이 없다고 가정해서 abstract 키워드를 사용해 추상 키워드로 만들어준다.
 .....
}

 

 

이후 Item 클래스를 상속받을 서브 타입 클래스인 Album, Book, Movie 클래스를 생성하여 논리 모델에 맞게 코드를 작성해준다.

- Album.java

@Entity
public class Album extends Item {

	private String artist;
	private String etc;

	// Getter, Setter
}

- Book.java

@Entity
public class Book extends Item {

	private String author;
	private String isbn;

	// Getter, Setter
}

- Movie.java

@Entity
public class Movie extends Item {

	private String director;
	private String actor;

	// Getter, Setter
}

 

위와 같이 Item 클래스를 슈퍼 클래스로 지정한 상속 관계에서 단일 테이블 전략을 활용하여 코드를 작성해 준 후 애플리케이션을 실행 해주면 아래와 같은 hibernate SQL 을 출력하는 것을 볼 수 있다.

-> createdBy 와 같이 BaseEntity 에서 상속 받은 필드들 까지 포함하여 테이블이 생성되는 것을 볼 수 있다.

Hibernate: 
    
    create table Item (
       DTYPE varchar(31) not null,
        ITEM_ID bigint not null,
        createdBy varchar(255),
        createdDate timestamp,
        lastModifiedBy varchar(255),
        lastModifiedDate timestamp,
        name varchar(255),
        price integer not null,
        stockQuantity integer not null,
        author varchar(255),
        isbn varchar(255),
        actor varchar(255),
        director varchar(255),
        artist varchar(255),
        etc varchar(255),
        primary key (ITEM_ID)
    )

 

이후 Main 클래스에 아래와 같은 코드를 작성해준 후 h2 console 에서 데이터가 테이블에 제대로 잘 들어갔는지 확인해보자.

- JpaMain.java

Book book = new Book();
book.setName("JPA");
book.setAuthor("김영한");

em.persist(book);

- hibernate SQL

Hibernate: 
    /* insert jpabook.jpahop.domain.Book
        */ insert 
        into
            Item
            (name, price, stockQuantity, author, isbn, DTYPE, ITEM_ID) 
        values
            (?, ?, ?, ?, ?, 'Book', ?) // Item 테이블에 insert 쿼리가 들어가는 것을 확인할 수 있다.

- h2 console

 

위의 콘솔 select 결과를 통해 슈퍼 타입 테이블이 단일 테이블 전략으로 생성되었고, 데이터 또한 잘 삽입 되었으며, 데이터가 삽입되지 않은 필드들은 null 값이 들어가 있는 것을 확인할 수 있다.(not null 제약조건 사용불가)