저번 게시글에서 DB 저장 시 원하는 코드 값이 아닌 숫자값이 그대로 DB에 저장되고 있는 이슈를 확인해보았습니다.
이번엔 Enum을 활용하여 개발자의 의도대로 데이터를 insert하는 방법을 알아보겠습니다.
1. 의도대로 Insert 되지 않고 있는 필드들.. - @Id, @Enumerated

@Entity
@Table(name = "post")
@Getter
@NoArgsConstructor(access = AccessLevel.PROTECTED)
@IdClass(PostId.class)
public class Post {
@Id
@Enumerated(EnumType.STRING) // 왜 적용 조차 안되지..
@Column(name = "category_code")
private CategoryCode categoryCode;
@Id
@Enumerated(EnumType.STRING) // 왜 적용 조차 안되지..
@Column(name="some_code")
private SomeCode someCode;
@Enumerated(EnumType.STRING) // 코드값으로 적용은 어떻게 하지..
@Column(name = "expenditure_code")
private ExpenditureCode expenditureCode;
//...
일단 우리는 위의 코드와 DB 결과를 통해 문제 상황을 대략 이렇게 정리해볼 수 있겠습니다.
문제 1) @Id애노테이션과 @Enumerated애노테이션은 같이 적용되지 않는다.
문제 2) @Enumerated(EnumType.STRING)은 단순히 Enum의 필드 name을 삽입시키는 역할을 한다.
아래에서 이를 검증해보겠습니다.
해결 방안) @Converter를 통한 Enum 코드값 컨버팅
여기서 필요한 것이 JPA가 제공해주는
jakarta.persistence.Converter 입니다.
위의 설명을 보시면 Converter는 @Id와, @Enumerated와는 함께 적용되지 않는다는 설명을 볼 수 있네요 !
현재의 어플리케이션 상황 (복합키 사용, DB 코드값 사용)에 맞지 않는 방법을 적용했던 것입니다..!
그럼 @Converter를 사용해볼까요?
@Converter(autoApply = true) // autoApply 옵션이 없으면 엔티티 필드에 @Convert를 각각 선언하여 적용
public class SomeCodeConverter implements AttributeConverter<SomeCode, String> {
@Override
public String convertToDatabaseColumn(SomeCode attribute) {
// DB에 저장 시 Enum -> 코드 변환
return attribute != null ? attribute.getCode() : null;
}
@Override
public SomeCode convertToEntityAttribute(String dbData) {
if (dbData == null) {
return null;
}
return Arrays.stream(SomeCode.values())
// 프로그램에서 조회 시 코드 -> Enum 변환
.filter(someCode -> someCode.getCode().equals(dbData))
.findFirst()
.orElse(null);
}
}
cf) 실수로 복합키 설정 클래스의 필드에 @Id 를 붙이지 마세요!
위의 문서에서 보았듯, Converter와 함께 적용되지 않습니다. @Id는 엔티티 필드에 붙이는 것으로 충분합니다.
마찬가지로, Id클래스에 적용한 Enum이 Converter가 필요 없는 경우 해당 Id클래스에서 @Enumerated(EnumType.STRING)을 적용해주세요!
@Getter
@AllArgsConstructor
@NoArgsConstructor
public class PostId implements Serializable {
//@Id
@Column(name = "category_code")
private CategoryCode categoryCode;
//@Id
//@Enumerated(EnumType.STRING) 만약 컨버터 사용하지 않는 경우 이곳에 Enumerated 설정하기
@Column(name="some_code")
private SomeCode someCode;
}
//..
public class Post {
@Id
//@Enumerated(EnumType.STRING) 어차피 @Id와 @Enumerated는 중복 적용 안됨
@Column(name = "category_code")
private CategoryCode categoryCode;
@Id
//@Enumerated(EnumType.STRING) 어차피 @Id와 @Enumerated는 중복 적용 안됨
@Column(name = "some_code")
private SomeCode someCode;
//@Enumerated(EnumType.STRING) @Enumerated가 @Converter 보다 우선 적용이라 지워야함!!
@Column(name = "expenditure_code")
private ExpenditureCode expenditureCode;
//..
각각의 EnumConverter를 생성해준 후 다시 테스트 코드를 돌려보겠습니다.
@Test
public void 포스트_저장_테스트(){
Post post = Post.builder()
.categoryCode(CategoryCode.CUSTOMER_INQUIRY)
.someCode(SomeCode.THING)
.expenditureCode(ExpenditureCode.FOOD)
.title("테스트 제목")
.content("테스트 내용")
.createdAt(LocalDateTime.now())
.deleteType(DeleteType.N)
.build();
Post savedPost = postRepository.save(post);
assertThat(savedPost.getCategoryCode()).isEqualTo(CategoryCode.CUSTOMER_INQUIRY);
}
이제야 기대했던 코드값이 제대로 insert 되고 있는 것을 확인해볼 수 있었습니다 !!
이번 시리즈 글은 이 포스트에서 마무리 지어보겠습니다.
감사합니다~!
'백엔드 > Java' 카테고리의 다른 글
천사와 악마 사이 추상클래스... - 인터페이스 및 정적 유틸리티 클래스 비교 - 2 (5) | 2024.02.13 |
---|---|
천사와 악마 사이 추상클래스... - 인터페이스 및 정적 유틸리티 클래스 비교 - 1 (0) | 2024.02.01 |
[이넘아 놀자] 3. 코드값으로 되어있는 Enum의 경우 (1) | 2023.08.28 |
[이넘아 놀자] 2. 일단 만들까 이넘 (0) | 2023.08.28 |
[이넘아 놀자] 1. 기존 하드코딩되어 있던 코드 문제점 분석 (복합키+하드코딩) (0) | 2023.08.27 |