본문 바로가기

TroubleShooting

JPA - org.springframework.dao.DataIntegrityViolationException: not-null property references a null or transient value

도메인

package com.personal.board.domain;

import lombok.Getter;
import lombok.Setter;
import lombok.ToString;
import org.springframework.data.annotation.CreatedBy;
import org.springframework.data.annotation.CreatedDate;
import org.springframework.data.annotation.LastModifiedBy;
import org.springframework.data.annotation.LastModifiedDate;
import org.springframework.data.jpa.domain.support.AuditingEntityListener;

import javax.persistence.*;
import java.time.LocalDateTime;
import java.util.LinkedHashSet;
import java.util.Objects;
import java.util.Set;

@Getter
@ToString
@Table(indexes = {
        @Index(columnList = "title"),
        @Index(columnList = "hashtag"),
        @Index(columnList = "createdAt"),
        @Index(columnList = "createdBy"),
})
@EntityListeners(AuditingEntityListener.class)
@Entity
public class Article {

    @Id    //    primary key
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    private Long id;    //  게시글 ID

    @Setter @Column(nullable = false, length = 255) private String title;   //  제목
    @Setter @Column(nullable = false, length = 10000) private String content;   //  본문

    @Setter private String hashtag; //  해시태그

    //    양방향 바인딩
    @ToString.Exclude
    @OrderBy("id")
    @OneToMany(mappedBy = "article", cascade = CascadeType.ALL)
    private final Set<ArticleComment> articleComments = new LinkedHashSet<>();

    //  meta data
    @CreatedDate @Column(nullable = false) private LocalDateTime createdAt; //  생성일시
    @CreatedBy @Column(nullable = false, length = 100) private String createdBy; //  생성자
    @LastModifiedDate @Column(nullable = false) private LocalDateTime modifiedAt;   //  수정일시
   @LastModifiedBy @Column(nullable = false, length = 100) private String modifiedBy;   //  수정자

    protected Article() {
    }

    private Article(String title, String content, String hashtag) {
        this.title = title;
        this.content = content;
        this.hashtag = hashtag;
    }

    public static Article of(String title, String content, String hashtag) {
        return new Article(title, content, hashtag);
    }

    @Override
    public boolean equals(Object o) {
        if (this == o) return true;
        if (!(o instanceof Article article)) return false;
        return id != null && id.equals(article.id);
    }

    @Override
    public int hashCode() {
        return Objects.hash(id);
    }
}

 

JpaConfig

package com.personal.board.config;

import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.data.domain.AuditorAware;
import org.springframework.data.jpa.repository.config.EnableJpaAuditing;
import java.util.Optional;

@EnableJpaAuditing
@Configuration
public class JpaConfig {

    public AuditorAware<String> auditorAware() {   //  TODO: 스프링 시큐리티로 인증 기능을 붙이게 될 때, 수정
        return () -> Optional.of("seeman94");
    }
}

라고 했을 때 insert 테스트를 실행해보면

 

    @DisplayName("insert test")
    @Test
    void givenTestData_whenInsert_thenWorksFine() {
        //  given
        long previousCount = articleRepository.count();

        //  when
        Article savedArticle = articleRepository.save(Article.of("new title", "new content", "#spring"));

        //  then
        assertThat(articleRepository.count()).isEqualTo(previousCount + 1);

    }

org.springframework.dao.DataIntegrityViolationException: not-null property references a null or transient value : com.personal.board.domain.Article.createdBy; nested exception is org.hibernate.PropertyValueException: not-null property references a null or transient value : com.personal.board.domain.Article.createdBy

 

위와 같은 오류메시지가 나온다. 보면 createdBy가 null 이어서 나오는 오류인데 이는 jpaConfig를 잘못 작성해서 발생하는 오류이다.

 

@Bean을 붙이지 않아서 발생하는 오류로 JpaConfig가 기본 작성자를 만들어주는(위의 경우 seeman94) 기능으로 생성자 혹은 수정자가 null이 되지 않게 만든다.

 

@Bean 을 붙이고 실행하면

 

테스트 성공