문제
게시판의 게시물등의 Entity 를 만들때 생성일시와 마지막으로 수정한 일시를 추가하고 싶다.
Entity 정의
채용플랫폼의 지원서 테이블을 만들어보고자 한다.
@AllArgsConstructor
@NoArgsConstructor
@Entity
public class Application {
@GeneratedValue(strategy = GenerationType.IDENTITY)
@Id
private Long applicationId;
// @Column(nullable = false)
// private Date dateCreated;
// 이렇게 꼭 멤버 선언을 해줘야 할까?
// @Column(nullable = false)
// private Date lastUpdated;
@Column(nullable = false)
private Integer bit;
@Column(nullable = false)
private String question1;
@Column(nullable = false)
private String question2;
@Column(nullable = false)
private String question3;
@Column(nullable = false)
private String educationLevel;
@Column(nullable = false)
private String militaryService;
원래는 주석처리한 저 두개를 선언해서 관리해야했는데, 그러지 않아도 된다고 한다
EnableJpaAuditing 어노테이션을 이용할 수 있도록 하자!
BaseTimeEntity 추상클래스를 만든다.
package com.hanium.hfrecruit.domain;
import org.springframework.data.annotation.CreatedDate;
import org.springframework.data.annotation.LastModifiedDate;
import org.springframework.data.jpa.domain.support.AuditingEntityListener;
import javax.persistence.EntityListeners;
import javax.persistence.MappedSuperclass;
import java.time.LocalDateTime;
/**
* '@MappedSuperclass' : JPA Entity 클래스들이 BaseTimeEntity를 상속할 경우 필드들(createdDate, modifiedDate)도 칼럼으로 인식하도록 합니다.
* '@EntityListeners(AuditingEntityListener.class)': BaseTimeEntiy 클래스에 Auditing 기능을 포함시킵니다.
* '@CreatedDate': Entity가 생성되어 저장될 때 시간이 자동 저장됩니다.
* '@LastModifiedDate': 조회한 Entity의 값을 변경할 때 시간이 자동 저장됩니다.
*/
@MappedSuperclass
@EntityListeners(AuditingEntityListener.class)
public abstract class BaseTimeEntity {
@CreatedDate
private LocalDateTime createdDate;
@LastModifiedDate
private LocalDateTime modifiedDate;
public LocalDateTime getCreatedDate() {
return createdDate;
}
public LocalDateTime getModifiedDate() {
return modifiedDate;
}
}
velog.io/@conatuseus/2019-12-06-2212-%EC%9E%91%EC%84%B1%EB%90%A8-1sk3u75zo9
LastModifiedDate 어노테이션이 붙으면 엔티티 값 수정시 알아서 변경을 시켜준다.
내가 일일이 기록을 하는 방법을 구현할 필요가 없는것...!
Entitiy 클래스에 상속이 되도록 하자
public class Application extends BaseTimeEntity {
...
}
그리고 위 주석처리된 부분을 지워보도록 하자
테스트 코드를 작성해 단위 테스트를 해보자
package com.hanium.hfrecruit.repository;
import com.hanium.hfrecruit.domain.application.Application;
import com.hanium.hfrecruit.domain.application.ApplicationRepository;
import org.junit.jupiter.api.Test;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;
import java.time.LocalDateTime;
import java.util.List;
@SpringBootTest
public class ApplicationTest {
@Autowired
ApplicationRepository applicationRepository;
@Test
public void BaseTimeEntity_등록() {
//given
LocalDateTime now = LocalDateTime.of(2019, 12, 6, 0, 0, 0);
applicationRepository.save(new Application());
//when
List<Application> applications = applicationRepository.findAll();
//then
Application app = applications.get(0);
System.out.println(">>>>> createDate = "+app.getCreatedDate() + ", modifiedDate = "+app.getModifiedDate());
// assertThat(application.getCreatedDate()).isAf;
// assertThat(application.getModifiedDate()).isAfter(now);
}
}
하지만 에러가 발생한다. 왜일까?
org.springframework.dao.DataIntegrityViolationException: not-null property references a null or transient value : com.hanium.hfrecruit.domain.application.Application.bit; nested exception is org.hibernate.PropertyValueException: not-null property references a null or transient value : com.hanium.hfrecruit.domain.application.Application.bit
Non Null 인 프로퍼티에 대해 적절하게 처리를 안했기 때문. 단순히 new Application() 으로는 생성할 수 없는 듯 하다.
빌더를 통해 entity save 테스트를 해보자
Non Null 인 멤버에 대해 단순히 객체 생성으로 테스트를 하면 에러가 난다. 그러니 빌더를 통해 적절히 객체를 생성할 수 있도록 하자!
@Builder 어노테이션 사용을 위해서는 Lombok 라이브러리가 필요하다.
https://projectlombok.org/features/Builder
빌더 어노테이션을 통해 모델의 객체 생성을 직관적으로 할 수 있다.
@Builder
public Application(Integer bit,String question1,String question2,
String question3,String educationLevel, String militaryService)
{
this.bit = bit;
this.question1 = question1;
this.question2 = question2;
this.question3 = question3;
this.educationLevel = educationLevel;
this.militaryService = militaryService;
}
}
Entity 클래스의 최하단에 위와 같은 함수를 만들어주자!
필요한 parameter 들은 선택해서 만들 수 있다.
package com.hanium.hfrecruit.repository;
import com.hanium.hfrecruit.domain.application.Application;
import com.hanium.hfrecruit.domain.application.ApplicationRepository;
import org.junit.jupiter.api.Test;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;
import java.time.LocalDateTime;
import java.util.List;
@SpringBootTest
public class ApplicationTest {
@Autowired
ApplicationRepository applicationRepository;
@Test
public void BaseTimeEntity_등록() {
//given
LocalDateTime now = LocalDateTime.of(2019, 12, 6, 0, 0, 0);
Application application = Application.builder().bit(0)
.question1("이 회사에 지원한 동기는?")
.question2("대학교 생활 중 가장 뜻깊었던 성취는?")
.question3("우리 회사에서 어떤 사람으로 성장하고 싶은지?")
.educationLevel("석사졸")
.militaryService("육군 만기 전역")
.build();
applicationRepository.save(application);
//when
List<Application> applications = applicationRepository.findAll();
//then
Application app = applications.get(0);
System.out.println(">>>>> createDate = "+app.getCreatedDate() + ", modifiedDate = "+app.getModifiedDate());
// assertThat(application.getCreatedDate()).isAf;
// assertThat(application.getModifiedDate()).isAfter(now);
}
}
new Application() 대신 @Builder 를 통해 만든 객체를 담아준다.
마지막으로 Main 함수에 @EnableJpaAuditing 어노테이션을 붙여준다
@EnableJpaAuditing
@SpringBootApplication
public class HfrecruitApplication {
public static void main(String[] args) {
SpringApplication.run(HfrecruitApplication.class, args);
}
}
자 이제 Test를 돌려보자.