회사 코드를 작성하다가 Jpa Entity를 단방향 OneToMany 관계로 설정할 일이 있었는데 "Field doesn't have a default value 오류가 계속 발생했습니다.
문제가 되었던 코드는 아래와 같습니다.
@Getter
@Entity
public class Test {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;
@OneToMany(orphanRemoval = true, cascade = CascadeType.ALL)
@JoinColumn(name = "TEST_ID")
private List<TestOneToMany> tests = new ArrayList<>();
}
@Getter
@Entity
public class TestOneToMany {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;
}
일단 저는 ddl auto를 사용하지 않고 직접 ddl을 넣어 주었습니다. ddl은 아래와 같습니다.
CREATE TABLE test (
id BIGINT AUTO_INCREMENT PRIMARY KEY
);
CREATE TABLE test_one_to_many (
id BIGINT AUTO_INCREMENT PRIMARY KEY,
TEST_ID BIGINT NOT NULL
);
결론 부터 말하자면 test_one_to_many 테이블의 TEST_ID가 NOT NULL로 설정되어있기 때문입니다.
@JoinColumn 어노테이션을 살펴보면 nullable이 true로 default 설정이 되어있습니다. 만약에 ddl auto를 사용했다면 test_one_to_many table의 TEST_ID 컬럼이 nullable하게 설정되기 때문에 아무 문제 없겠지만 직접 스키마를 설정해 주었기 때문에 nullable을 false로 설정해야 정상적으로 동작합니다.
일단 OneToMany에서 영속성을 관리한다면 insert할 때 먼저 TestOneToMany를 insert하고 TEST_ID를 update 하는 방식으로 동작합니다. 왜냐하면 TestOneToMany Entity에는 Test에 대한 정보가 없기 때문에 insert를 하고 연관관계를 맺기 위해 TEST_ID update 해주기 때문입니다. 그래서 실제 쿼리를 보면 아래와 같이 나옵니다.
Hibernate:
select
t1_0.id
from
test t1_0
where
t1_0.id=?
Hibernate:
select
t1_0.test_id,
t1_0.id
from
test_one_to_many t1_0
where
t1_0.test_id=?
Hibernate:
insert
into
test_one_to_many
(test_id,id)
values
(?,default)
Hibernate:
update
test_one_to_many
set
test_id=?
where
id=?
FK 같은 경우는 제약조건으로만 본다면 Nullable해도 상관없습니다. 하지만 제 경우는 게시글과 댓글 같은 관계라서 게시글이 없이 댓글이 존재할 수가 없기 때문에 NOT NULL로 설정 해야합니다.
그래서 비즈니스에 맞게 설정 해야합니다.
성능상으로 본다면 ManyToOne으로 설정하는게 맞지만 도메인적으로 봤을 때 ManyToOne으로 설정하면 많이 어색하기도했고 비즈니스적으로 성능이 중요하게 변경된다면 이때 수정해도 크게 문제가 없기 때문에 OneToMany로 설정하게되었습니다.