JPA에서 Column Default 값이 적용안될 때 해결방법

김찬미·2024년 2월 20일
0

Error 해결

목록 보기
6/8
post-custom-banner

스프링부트 JPA 컬럼 디폴트가 안 먹는다.

방법 1.

@DynamicInsert, @DynamicUpdate을 이용하자

null 인 필드값이 insert 나 update 시 제외되게 하는 방법인 org.hibernate.annotations. 패키지의

@DynamicInsert (insert시 null인 필드 제외)
@DynamicUpdate (update시 null인 필드 제외)

를 사용한다.

@Entity
@Data
@Builder
@DynamicInsert
@AllArgsConstructor
@NoArgsConstructor
@Table(name = "user")
public class User {
    ...    
}

그리고 default값을 적용하고 싶은 컬럼에
@ColumnDefault("원하는 값")
을 붙여주면 된다.

@Column(name = "follow_cnt")
@ColumnDefault("0")
private Integer followCnt; // 팔로워 수

그러나 난 장렬하게 실패했다.
이유를 추측하자면 나는 빌더 방식

@Transactional
public UserResponseDto signUp(UserRequestDto userRequestDto) throws Exception {

        if (userRepository.findByUserEmail(userRequestDto.getUserEmail()).isPresent()) {
            throw new Exception("이미 존재하는 이메일입니다.");
        }

        if (userRepository.findByNickname(userRequestDto.getNickname()).isPresent()) {
            throw new Exception("이미 존재하는 닉네임입니다.");
        }

        User user = User.builder()
                .userName(userRequestDto.getUserName())
                .userEmail(userRequestDto.getUserEmail())
                .password(userRequestDto.getPassword())
                .nickname(userRequestDto.getNickname())
                .userType(Role.USER)
                .build();

        user.passwordEncode(passwordEncoder);
		userRepository.save(user);

        return new UserResponseDto(user);
    }

(UserService의 회원가입 로직)

을 사용하는데, 이때 초기화가 되버리기 때문에(Null인 컬럼 발생)
Entity에서 설정을 해도 소용이 없는 것 같았다.

방법 2.

columnDefinition 사용

    @Column(name = "follow_cnt", columnDefinition = "integer default 0")
    private int followCnt;

이것 또한 위 사유와 마찬가지로 실패했다.
남들은 다 된다는데 왜 나만... 이라고 생각하며 좌절할 때 즈음 새로운 글을 발견했다.

방법 3. (드디어 성공!)

@PrePersist, @PreUpdate 사용하기

persist 되기 직전 호출되는 어노테이션 @PrePersist을 사용하는 방법이다.

@Entity
@Data
@Builder
@AllArgsConstructor
@NoArgsConstructor
@Table(name = "user")
public class User {

    ...

    /**
     * insert 되기전 (persist 되기전) 실행된다.
     * */
    @PrePersist
    public void prePersist() {
        this.likeCount = this.likeCount == null ? 0 : this.likeCount;
    }
}

User엔 이렇게 prePersist()를 만들어주고

    @Transactional
    public UserResponseDto signUp(UserRequestDto userRequestDto) throws Exception {

        if (userRepository.findByUserEmail(userRequestDto.getUserEmail()).isPresent()) {
            throw new Exception("이미 존재하는 이메일입니다.");
        }

        if (userRepository.findByNickname(userRequestDto.getNickname()).isPresent()) {
            throw new Exception("이미 존재하는 닉네임입니다.");
        }

        User user = User.builder()
                .userName(userRequestDto.getUserName())
                .userEmail(userRequestDto.getUserEmail())
                .password(userRequestDto.getPassword())
                .nickname(userRequestDto.getNickname())
                .userType(Role.USER)
                .build();

        user.passwordEncode(passwordEncoder);

        User resultUser = userRepository.save(user);
        assertThat(resultUser.getFollowCnt(), Is.is(0)); // 이 부분!

        return new UserResponseDto(user);
    }

평소처럼 userRepository.save()를 해주고 나서 assertThat을 해주면 된다.
빌더가 작동된 후, null인 값에만 default 0을 적용해주기 때문에 제대로 DB에 저장된다!


(위는 1번 방식으로 시도했을 때, 아래는 3번 방식으로 시도했을 때 결과값)

간단한 기초 중에 기초지만 새롭게 Default값을 설정하는 방식을 알게되어서 좋았다.

참고 : https://dotoridev.tistory.com/6

profile
백엔드 개발자
post-custom-banner

0개의 댓글