Backend

[JPA] 상속관계 매핑, 공통 속성 매핑

연_우리 2022. 2. 21. 20:16
반응형

목차

     

     

     

    객체의 상속관계

    extends로 지원해준다.

    @Entity
    public class Item {
        @Id @GeneratedValue
        @Column(name = "item_id")
        private Long id;
        private String name;
        private int price;
        private int stockQuantity;
    }
    
    @Entity
    public class Album extends Item{
        private String artist;
    }
    
    @Entity
    public class Movie extends Item{
        private String director;
        private String actor;
    }
    
    @Entity
    public class Book extends Item{
        private String author;
        private String isbn;
    }

     

    DB에서 슈퍼타입-서브타입 모델을 구현하는 방법

    관계형 데이터베이스는 상속관계가 없지만

    상속과 유사한 슈퍼타입-서브타입 모델링 기법이 있다.

     

    JPA에서는 아래 3가지를 모두 지원해주며, @Inheritance 어노테이션으로 표현할 수 있다.

     

     

    1. 통합 테이블로 만들어 조인없이 결과를 얻어오는 방법

        장점 : 조인이 없어서 조회 성능이 빠르다.

        단점 : 자식 엔티티가 매핑한 컬럼은 모두 null이 허용된다.

                테이블이 너무 커질 수 있다. 상황에 따라서는 조회 성능이 오히려 느려질 수 있다.

     

        JPA에서 기본전략이다. Item 엔티티에 @Entity만 사용하거나

        @Inheritance(strategy = InheritanceType.SINGLE_TABLE) 로 지정한 경우에 통합 테이블로 만들어준다.

     

    2. 각각의 테이블로 나누되 테이블마다 컬럼을 중복하는 방법

        장점 : 통합 테이블보다 테이블이 나뉘어져 컬럼에 not null제약조건을 사용할 수 있다.

        단점 : 객체지향에서는 Item으로 Album, Book, Movie를 조회할 수 있다.

                하지만 각 테이블마다 나뉘어진 상태에서 Item으로 조회하게되면

                모든 테이블을 조회해서 결과를 가져와야한다(Union SQL필요)

                => DB설계자, ORM 전문가 모두 추천하지 않는 방법이다!!

     

        Item엔티티에 @Inheritance(strategy = InheritanceType.TABLE_PER_CLASS)로 지정해준다.

        객체에서는 Item엔티티에 abstract 키워드를 붙여서 추상클래스로 만들어준다.

        그러면 extends를 사용하면서, Item테이블은 생성되지 않는다.

     

    3. 각각의 테이블로 나누되 중복 컬럼은 공통 테이블로 분리하고 조인으로 결과를 얻어오는 방법

       장점 : 정규화를 통해 저장공간이 효율화된다.

       단점 : 조회 시 조인을 많이 사용하게되어 성능이 저하될 수 있다.

                데이터 저장 시 Insert문을 2번 호출한다.

     

       Item엔티티에 @Inheritance(strategy = InheritanceType.JOINED)로 지정해준다.

    @Entity
    @Inheritance(strategy = InheritanceType.JOINED)
    public class Item {
        @Id @GeneratedValue
        @Column(name = "item_id")
        private Long id;
        private String name;
        private int price;
        private int stockQuantity;
    }
    
    @Entity
    public class Movie extends Item{
        private String director;
        private String actor;
    }
    Movie movie = new Movie();
    movie.setName("아바타");
    movie.setPrice(10000);
    movie.setStockQuantity(10);
    movie.setActor("배우");
    movie.setDirector("작가");
    
    em.persist(movie);

     

    @DiscriminatorColumn

    데이터베이스 테이블을 조회했을 때, item에 입력된 값이 자식인 album, book, movie 중 어떤 것에 의해 작성되었는지를 표시해주는 컬럼을 추가해준다.

     

    부모 테이블에 설정한다.

    @DiscriminatorColumn을 설정했을 때 생기는 컬럼의 기본명은 DTYPE으로, (name = "~")으로 컬럼명을 변경할 수 있다.

    DTYPE에 들어가는 기본값은 엔티티명이다.

    @Entity
    @Inheritance(strategy = InheritanceType.JOINED)
    @DiscriminatorColumn
    public class Item {
        @Id @GeneratedValue
        @Column(name = "item_id")
        private Long id;
        private String name;
        private int price;
        private int stockQuantity;
    }
    
    @Entity
    public class Movie extends Item{
        private String director;
        private String actor;
    }

     

    @DiscriminatorValue

    @DiscriminatorColumn에 입력되는 값을 변경할 수 있다.

    자식테이블에 설정한다.

    @Entity
    @Inheritance(strategy = InheritanceType.JOINED)
    @DiscriminatorColumn
    public class Item {
        @Id @GeneratedValue
        @Column(name = "item_id")
        private Long id;
        private String name;
        private int price;
        private int stockQuantity;
    }
    
    @Entity
    @DiscriminatorValue("M")
    public class Movie extends Item{
        private String director;
        private String actor;
    }

     

     

    @MappedSuperclass

    기본적으로 필요한 createdBy, createTime, updatedBy...  등등 모든 엔티티에서 공통적으로 사용하는 컬럼들의 경우

    BaseEntity를 생성한 후 해당 어노테이션을 붙여준다.

     

    주의! @MappedSuperclass는 상속관계 매핑이 아니다. 

    자식 클래스에 컬럼정보만 제공해주는 것이다.

    직접 생성해서 사용할 일이 없으므로 추상 클래스를 권장한다.

    @MappedSuperclass
    public abstract class BaseEntity {
    
        private String createBy;
    
        @Column(name = "updateBy")
        private String update;
    }
    
    @Entity
    public class Member extends BaseEntity {
        @Id @GeneratedValue
        @Column(name = "member_id")
        private Long id;
        private String name;
    }

     

     

    반응형
    • 네이버 블러그 공유하기
    • 페이스북 공유하기
    • 트위터 공유하기
    • 구글 플러스 공유하기
    • 카카오톡 공유하기