[Spring] JPA Enum Converter를 사용하여 Entity Mapping하기(Feat. Parameter value [~] did not match expected type Error)

kindof

·

2022. 1. 25. 23:50

0. 문제

먼저 아래와 같은 상품게시물(ItemPost) 엔티티를 보겠습니다.

ItemPost Entity

ItemPost(상품게시물)은 자신의 Id, 게시물의 제목과 내용, 이미지 사진들, 그리고 해당 상품의 카테고리를 갖고 있는데요. 여기서 상품의 카테고리를 Enum 타입으로 관리하려고 했습니다. 간단히 두 개의 카테고리만 넣어놓고 테스트를 진행하겠습니다.

아이템 카테고리

 

그리고 아래와 같이 Enum 필드를 가진 엔티티를 해당 필드를 조건으로 하여 DB에서 조회하고 싶다고 해보겠습니다.

Controller
Service
Repository

위와 같이 컨트롤러, 서비스, 레포지토리 코드를 작성하고 아래와 같이 세 개의 기본 데이터를 넣어뒀습니다.

ItemPost 데이터

이제 Postman으로 SPORTS 카테고리를 갖는 아이템 게시물을 조회해보면 아래와 같은 에러가 발생합니다.

조회 실패

에러 내용을 자세히 보면, Parameter Value인 'SPORTS'가 ItemCategory 타입과 맞지 않다는 것을 알 수 있는데요. 이 에러를 보고 나면 위의 코드들이 잘못되었다는 사실을 깨달을 수 있습니다.

 

ItemPost 엔티티를 저장할 때 카테고리 필드는 String이 아니라 ItemCategory타입인데, 엔티티를 조회해올 때는 단순 String으로 조회하려고 했기 때문입니다.

 

따라서, 이 문제를 해결하기 위해 위 코드에서 몇 부분만 조금 수정해보려고 합니다.

 

 

1. @Eumerated(EnumType.STRING)

@Enumerated(EnumType.STRING)은 Enum 타입의 필드를 DB에 저장할 때 enum '이름'으로 매핑해주는 어노테이션입니다.

 

이 방법을 사용하면 저장된 Enum의 순서가 바뀌거나 enum이 추가되어도 Ordinal한 관점에서 달라지지 않기 때문에 안전하다는 장점이 있습니다(Default 설정은 Enum.ORDINAL로 되어 있습니다). 하지만, DB에 저장되는 데이터의 크기가 ORDINAL에 비해서는 크다는 문제점이 있습니다. 그럼에도 불구하고, Enum 타입으로 선언된 데이터가 그렇게 많지 않다면 DB에 미치는 메모리 문제가 그렇게 큰 이슈는 안될 것 같다고 생각했습니다.

 

어쨌든, 이 방법을 가지고 위 코드를 조금만 수정해보겠습니다.

ItemPost Repository

레포지토리에서 조회해올 때 파라미터의 타입을 String에서 ItemCategory로 바꿔주었습니다.

Service

그리고 Service 레이어에서 String 타입의 category를 Enum 타입으로 바꿔서 레포지토리에 파라미터로 넘겨줍니다.

Postman으로 테스트 성공

이제 원하는대로 결과가 나오는 것을 확인할 수 있습니다. 

 

하지만, 아래에서는 @Enumerated(EnumType.STRING) 대신에 'Converter'라는 도구를 이용해서 Enum 속성을 가진 엔티티를 다루는 방법에 대해 알아보려고 합니다.

 

 

2. Enum Converter

아래는 JPA에서 Enum 타입을 어떻게 관리하면 좋을지에 대해 찾아보다가 발견한 글입니다. 우아한형제들의 기술블로그 내용인데요.

 

Legacy DB의 JPA Entity Mapping (Enum Converter 편) | 우아한형제들 기술블로그

{{item.name}} 안녕하세요. 저는 우아한형제들 비즈상품개발팀의 이은경입니다. Legacy DB의 JPA Entity Mapping (복합키 매핑 편)에 이어 저는 DB의 코드값과 Java Enum을 연결해주는 과정에서 유용하게 사용

techblog.woowahan.com

이 글의 요지는 DB의 코드값과 Java Enum을 연결해주는 과정에서 @Convert를 사용하면 코드의 유지보수나 유연성이 늘어난다는 것이었습니다.

 

그래서 위 글을 바탕으로 제가 썼던 코드를 리팩토링해봤습니다.

ItemCategoryConverter

먼저 ItemCategoryConveter 클래스를 작성합니다. 이 클래스는 AttributeConverter를 상속하여 DB → Entity, Entity → DB로의 변환을 해주는 메서드인 converToDatabaseColumn()과 convertToEntityAttribute()를 오버라이딩합니다.

 

이제 ItemCategory로 가서 fromCode() 메서드를 작성하겠습니다.

ItemCategory
ItemPost

그리고 마지막으로 ItemPost 엔티티의 ItemCategory 필드에 있는 @Enumerated(EnumType.STRING) 대신 @Convert(converter = ItemCategoryConverter.class)를 사용합니다.

 

이제 Postman으로 똑같은 요청을 보내면 이전과 같이 원하는 결과를 얻을 수 있습니다.

Postman 조회 요청 - 성공

 

3. 나가면서

이번 포스팅에서 JPA에서 엔티티를 매핑할 때 Enum 필드를 어떻게 할 것인가에 대해 @Enumerated 어노테이션의 사용과 Converter 사용 방법에 대해 알아보았습니다.

 

사실 아래 이동욱님의 Enum 활용사례에 대한 글을 읽으면서, 저는 아직 'Enum을 하나도 제대로 사용하지 못하고 있구나'를 느꼈습니다.

 

Enum 활용사례 3가지

안녕하세요? 이번 시간엔 enum 활용사례를 3가지정도 소개하려고 합니다. 모든 코드는 Github에 있기 때문에 함께 보시면 더 이해하기 쉬우실 것 같습니다. (공부한 내용을 정리하는 Github와 세미

jojoldu.tistory.com

 

앞으로 더 많은 공부를 해보면서 오늘 소개한 Enum Converter를 좀 더 효과적으로 사용할 수 있는 시점에 대해 고민해보고, Enum 자체를 어떻게 사용하면 더 좋은 코드를 짤 수 있는지 배워야겠습니다.

 

감사합니다.