문제 상황
study 엔티티에 studyStatus 속성에 디폴트 값으로 TODO 로 설정하려고 아래와 같이 설정해주었다
@ColumnDefault("TODO")
@Enumerated(EnumType.STRING)
private StudyStatus studyStatus = StudyStatus.TODO; //강의 상태
근데 아래와 같은 오류 발생
Error executing DDL "create table study (likes integer default 0, progress integer default 0, study_id integer not null auto_increment, study_order integer, user_id integer, create_at datetime(6), update_at datetime(6), category varchar(10), study_title varchar(20) not null, description TEXT, study_img varchar(255) not null, study_link varchar(255), study_status enum ('DONE','IN_PROGRESS','TODO') default TODO, primary key (study_id)) engine=InnoDB" via JDBC [You have an error in your SQL syntax; check the manual that corresponds to your MySQL server version for the right syntax to use near 'TODO, primary key (study_id)) engine=InnoDB' at line 1]
원인
@ColumnDefault 역할에 대한 이해를 잘못하고 있었다.
이 어노테이션은 필드가 Null인 경우에 디폴트 값으로 세팅하지 않는다.
나는 테이블이 정의될 때 deafult 값으로 세팅되는 줄 알았다.
필드 주입으로 기본값 세팅 + @ColumnDefault 로 기본값 설정해서 오류가 난것아닐까.. 좀 더 찾아봐야할거같다
속성 디폴트값 지정 하는 방법
1. 엔티티 생성할 때 기본값 제공
private String firstName = "John Snow";
테이블 정의할 때 ddl을 보면 기본값으로 세팅해주지 않는다.
그럼 언제 디폴트 값이 들어가는가? `new` 를 통해서 엔티티를 생성할 때 기본값이 설정된다.
User user = new User();
user = userRepository.save(user);
assertEquals(user.getName(), "John Snow");
assertEquals(user.getAge(), 25);
assertFalse(user.getLocked());
}
ddl 을 보면 아래와 같이 기본값이 하나도 설정되어 있지 않다.
create table user
(
id bigint not null constraint user_pkey primary key,
name varchar(255),
age integer,
locked boolean
);
따라서 null로 재정의하면 엔티티가 오류 없이 저장된다. -> 개발자 의도와 상관없이 Null이 들어갈 수 있다..
2. sql table 정의할 때 넣어주기 (@Column 사용)
@Column(columnDefinition = "varchar(255) default 'John Snow'")
private String name;
위와 같이 설정하면 아래와 같이 테이블이 정의된다
create table user
(
id bigint not null constraint user_pkey primary key,
name varchar(255) default 'John Snow',
age integer default 35,
locked boolean default false
);
엔티티를 저장할 때 주언진 열을 null 로 설정할 수 없다.
3. @ColumnDefault 사용
이 어노테이션은 jpa 레벨에서 디폴트 값이 세팅된다. (@Column은 ddl 로 처음 테이블정의할 때 적용됨)
@Entity
@Table(name="users_entity")
public class UserEntity {
@Id
private Long id;
@ColumnDefault("John Snow")
private String name;
@ColumnDefault("25")
private Integer age;
@ColumnDefault("false")
private Boolean locked;
}
create table users_entity
(
age integer default 25,
locked boolean default false,
id bigint not null,
name varchar(255) default 'John Snow',
primary key (id)
)
여기서 조심해야할 점은
insert 할 때 id 속성만 추가할 경우 다른 필드는 @ColumnDefault에서 설정한 디폴트 값이 들어간다.
INSERT INTO users_entity (id) VALUES (?);
insert 에 일부 속성만 포함해서 추가할 경우, 추가되지 않는 다른 속성은 Null 로 설정되고 디폴트 값으로 들어가지 않는다.
4. @PrePersist
@Prepersist는 콜백을 사용하여 기본값 처리 가능
엔티티가 제대로 초기화 되지 않았거나 특정 필드가 null인 경우에도 기본값이 설정되도록 하려는 경우 유용하다
@Entity
public class UserEntity {
@Id
private Long id;
private String name;
private Integer age;
private Boolean locked;
@PrePersist
public void prePersist() {
if (name == null) {
name = "John Snow";
}
if (age == null) {
age = 25;
}
if (locked == null) {
locked = false;
}
}
}
복사
이 어노테이션이 붙은 메서드를 사용해서 엔티티를 데이터베이스에 저장하기 전에 기본값을 설정한다.
이렇게 하면 엔티티에 값이 들어오지 않았다면 모두 기본값으로 세팅하게 할 수 있다.
필드가 null로 설정되어 있어도 기본값으로 설정된 값으로 적용된다
해결
@Column(columnDefinition = "enum ('DONE','IN_PROGRESS','TODO') default 'TODO'")
@Enumerated(EnumType.STRING)
private StudyStatus studyStatus;