[JPA] Inheritance 엔티티도 jpaRepository를 적용시킬 수 있을까?

유알·2023년 8월 12일
0

[DB/JPA]

목록 보기
5/7

Intro

데이터 베이스를 설계할 때 다음과 같은 경우를 맞이 한다.

출처

그렇다 이런 관계를 가진 경우 객체에서는 상속 관계를 맺으면 되지만 테이블과 JPA는 어떻게 설계해야할까?

이런식으로 설계할 수 있고, 이를 JPA에서는 @Inheritance라는 어노테이션을 통해 지원한다.

상황

나는 아래와 같은 상황에서 Inheritance를 적용해서 설계를 개선하였다.
보면, 한개의 인가 테이블에 여러개의 인증 토큰들이 매달려있는 방식이다.

각각은 일대일 매핑으로 null을 허용하고 있었기 때문에, 다음과 같은 문제가 있다고 생각했다.

  • 많은 null 값으로 인한 낭비
  • 객체상에는 연관관계가 들어나지만, 테이블 상에서는 들어나지 않음
  • 많은 중복 컬럼, 이로 인한 유지보수의 어려움
  • 테이블을 조회시 항상 여러개의 join이 따라 붙어야함
  • 만약 앞으로 토큰의 타입이 여러개로 늘어나면, 난감함

그래서 다음과 같이 테이블 설계를 변경하였다.

그리고 Jpa 엔티티도 그에 맞게 교체하였다.

@Entity @Table(name = "token")
@Inheritance(strategy = InheritanceType.JOINED)
@DiscriminatorColumn(name = "dtype", discriminatorType = DiscriminatorType.STRING)
@Data @EqualsAndHashCode(of = "id")
@NoArgsConstructor
public abstract class CommonTokenEntity {
@DiscriminatorValue("access_token")
@Entity @Table(name = "access_token")
@Data
@EqualsAndHashCode(callSuper = true)
@NoArgsConstructor
public class AccessTokenEntity extends CommonTokenEntity {

spring data jpa의 repository 생성 가능?

그렇다 이런 궁금증이 들었다. 그렇다면, 추상클래스이자 부모 클래스인 CommonTokenEntity로 Repository를 생성할 수 있는가?

결과부터 말하면, 있다. 심지어 마음에 들게 동작한다.

내가 작성한 테스트 코드를 한번 보자

@ActiveProfiles("test")
@ExtendWith(SpringExtension.class)
@DataJpaTest
class CommonTokenRepositoryTest {

    @PersistenceContext
    EntityManager em;

    @Autowired
    CommonTokenRepository commonTokenRepository;

    @Test
    @DisplayName("Inheritance Entity 도 repository 로 조회가 가능한지 테스트")
    void inheritanceEntityRepositoryAvailable(){
        //given
        OAuth2AuthorizationEntity authorization = TestEntityFactory.getOAuth2AuthorizationEntity(em);
        em.persist(authorization);

        AccessTokenEntity accessTokenEntity = TestEntityFactory.getAccessTokenEntity(authorization);
        em.persist(accessTokenEntity);

        //when
        CommonTokenEntity commonTokenEntity = commonTokenRepository.findById(accessTokenEntity.getId())
                .orElseGet(() -> fail("조회 실패"));

        //then
        assertTrue(commonTokenEntity instanceof AccessTokenEntity);
        String type = commonTokenEntity.getType();
        System.out.println(type);
        AccessTokenEntity castedEntity = (AccessTokenEntity) commonTokenEntity;
        assertNotNull(castedEntity.getTokenType());
        assertEquals(commonTokenEntity.getAuthorization(), authorization);

    }

}
  • 일단 조회도 가능하고
  • 거기에다가 instanceof 로 자식클래스의 타입도 추론 가능하다
  • 캐스팅을 하게 되면, 자식 클래스에만 있는 필드도 조회가 가능하다.

이 모든 것이 저 Inheritance 추상클래스의 Repository에서 조회가 된 것이다.

따라서 Inheritance를 통해 엔티티를 설계하면, 한개의 Repository를 통해 좀더 관계 있게 엔티티를 조회할 수 있다.

전체코드는 -> 링크

profile
더 좋은 구조를 고민하는 개발자 입니다

1개의 댓글

comment-user-thumbnail
2023년 8월 12일

잘 읽었습니다. 좋은 정보 감사드립니다.

답글 달기