본문 바로가기

Spring/Spring Data JPA

@DiscriminatorColumn을 이용한 Spring Data Jpa 상속관계(Inheritance) 매핑 하기

728x90

Spring Data Jpa 상속관계(Inheritance) 매핑 하기

 

Spring Data Jpa를 이용해 Restful Api를 구축하는데 Domain설계부터 다시 하고있습니다. 그런데 Dynamic으로 해야 할 일이 있어서 이 기능을 알아보게 되었습니다.

 

시나리오

교보문고에 가면 물건들(Item)을 파는데 앨범(Album)도 판다.

 

사용한것

Spring Data Jpa, Lombok.

MySql

Lombok을 사용했기 때문에 @Data 어노테이션이 있습니다.

사용한 전략은 조인 전략 매핑을 사용했습니다.

 

구조

item 이라는 table이 parent(부모), album 이라는 table이 child(자식)구조입니다.

 

Table

item과 album 2개만 해보았습니다.

item

CREATE TABLE `item` (
 `id` BIGINT(20) NOT NULL AUTO_INCREMENT,
 `name` VARCHAR(50) NOT NULL,
 `price` INT(11) NOT NULL,
 `dtype` VARCHAR(50) NOT NULL,
 PRIMARY KEY (`id`)
)

COLLATE='utf8_general_ci'
ENGINE=InnoDB
AUTO_INCREMENT=2;

item(부모) 테이블을 만들 때 dtype컬럼을 추가 해주고 타입은 VARCHAR로 합니다.

 

album

CREATE TABLE `album` (
 `id` BIGINT(20) NOT NULL,
 `artist` VARCHAR(50) NOT NULL
)
COLLATE='utf8_general_ci'
ENGINE=InnoDB;

table에 id는 만들어 주어야 합니다. id필드 이름은 부모 테이블의 id필드 이름과 동일한 이름을 쓰는게 기본값입니다. 이걸 바꿀려면 다른 어노테이션을 써야합니다.

 

엔티티(Entity)

Item.java

@Entity
@Inheritance(strategy=InheritanceType.JOINED)
@DiscriminatorColumn(name="dtype")
@Data
public abstract class Item {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
@Column(name="id")
private long id;
private String name;
private int price;

    }

부모 클래스는 추상(abstract) 클래스로 선언 해야 합니다.

 

Album.java

@Entity
@DiscriminatorValue("A")
@Data
public class Album extends Item {
private String artist;

   }

자식 클래스는 Id를 만들면 안됩니다.

 

리포지토리 인터페이스(Repository)

public interface AlbumRepository extends JpaRepository<Album, Long> { }

자식 클래스로 선언해야한다. 부모클래스로는 선언할 필요가 없습니다. ItemRepository 가 필요가 없음.

 

실행 코드

ItemRepositoryTest.java

    @RunWith(SpringRunner.class)

@SpringBootTest
@ActiveProfiles("dev")
public class ItemRepositoryTest {

    @Autowired
    AlbumRepository albumRepository;

    @Test
    public void saveAndFind() throws Exception {

        Album album = new Album();
        album.setName("hello");
        album.setPrice(2000);
        album.setArtist("kyeongrok");

        albumRepository.save(album);

    }
}

Test Class로 만들었는데 안에 있는 내용만 main()에 넣고 써도 됩니다.

부모 클래스(Item)가 abstract Class이므로 사용은 구현체인 자식(Album) 클래스를 사용해주는게 흐름상도 맞고 실제로도 맞는 사용 방법입니다.

이 예제를 마땅히 찾을만한데가 없어서 이 포스트를 쓰는것도 있습니다.

 

결과

Hibernate: insert into item (name, price, dtype) values (?, ?, 'A')

Hibernate: insert into album (artist, id) values (?, ?)

 

했던 났던 실수

1.부모 클래스를 추상(abstract) 클래스로 선언 하지 않은 것

2. missing column [id] jpa inheret - 1번 문제 때문에 났음

3. java.sql.SQLException: Parameter index out of range - 1번 문제 때문에 났음

4.자식 클래스에 @Id 넣은것 - 넣으면 안됨

5.부모 클래스로 Repository만든 것. ItemRepository 가 필요가 없음.

 

 

 

 

 

 

728x90
  • Q 2021.01.18 23:30

    왜 ItemRepository가 필요 없나요??

    • KyeongRok Kim 2021.01.18 23:57 신고

      아주 오래전에 있었던 이슈네요. 그때 후루룩 정리해서 잘 기억은 나지 않지만,

      제가 고전했던 이유는 부모 클래스인 ItemRepository로 db 액세스를 시도했기 때문입니다.

      Item클래스는 추상클래스 이기 때문에 Item클래스를 구현한 클래스인 Album Repository만 있으면 Item과 Album table에 crud를 할 수 있습니다.

블로그 주인장입니다. 원하시는 정보는 얻으셨나요? 이 포스트에서 추가로 필요한 정보가 있으시면 여기에 남겨주세요.