Jpa OneToMany Field 'doesn't have a default value 이슈

Jaeyoung·2024년 1월 15일
0
post-thumbnail

회사 코드를 작성하다가 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로 설정해야 정상적으로 동작합니다.

왜 JoinColumn에서 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=?

TEST_ID를 NOT NULL로 지정 해야할까?

FK 같은 경우는 제약조건으로만 본다면 Nullable해도 상관없습니다. 하지만 제 경우는 게시글과 댓글 같은 관계라서 게시글이 없이 댓글이 존재할 수가 없기 때문에 NOT NULL로 설정 해야합니다.

그래서 비즈니스에 맞게 설정 해야합니다.

ManyToOne으로 하면 안되는 것인가?

성능상으로 본다면 ManyToOne으로 설정하는게 맞지만 도메인적으로 봤을 때 ManyToOne으로 설정하면 많이 어색하기도했고 비즈니스적으로 성능이 중요하게 변경된다면 이때 수정해도 크게 문제가 없기 때문에 OneToMany로 설정하게되었습니다.

profile
Programmer

0개의 댓글