쌩로그

JPA Entity에서 참조를 맺는 @JoinColumn 애너테이션에 대한 오개념 정리(조금 더 정확히는 name 속성에 관하여) 본문

Spring/JPA

JPA Entity에서 참조를 맺는 @JoinColumn 애너테이션에 대한 오개념 정리(조금 더 정확히는 name 속성에 관하여)

.쌩수. 2024. 4. 3. 00:48
반응형

목록

  1. 포스팅 개요
  2. 본론
      2-1. 문제 인식 배경
     &nbsp2-2. 문제 발생의 원인
       2-3. 문제 발생을 일으키게 된 이유
  3. 요약

1. 포스팅 개요

해당 포스팅은 제목과 같이 JPA Entity에서 외래 키와 참조를 맺는 @JoinColumn 애너테이션에 대한 오개념을 바로잡기 위한 포스팅이다.

2. 본론

2-1. 문제 인식 배경

현재 회사에서 진행 중인 프로젝트는 여러 사용자가 하나의 데이터에 접근해서 수정할 수도 있고, 삭제할 수도 있다.

즉, A 사용자가 생성하고 B 사용자가 수정했다가 C 사용자가 삭제할 수도 있는 구조다.
(사내 서비스라 요구사항이 이렇다.)

따라서 학습차원에서 했던 프로젝트처럼 어떤 게시물에 대해서 작성자만 접근할 수 있는 구조가 아니라서 생성날짜 및 수정날짜보단 누가 데이터를 생성했고, 수정했는지가 더 중요하다.

그래서 이에 맞게 유지보수를 하던 중 생성자와 수정자가 Member를 참조하는 외래키로 하는 것이 좋을 것 같다는 피드백을 얻었고,

그에 따라 어떤 사용자의 요청에 의해 생성되는 데이터 DB에서 매핑되는 테이블에서 생성자와 수정자의 의미를 지니는 외래 키를 두기 위해서 Member의 기본 키에 두 번을 참조하게 했다.

게시판을 예로 든 코드인데, 다음과 같다.

@Getter
@Entity
@NoArgsConstructor(access = AccessLevel.PROTECTED)
public class Board {

    @Id @GeneratedValue(strategy = GenerationType.IDENTITY)
    @Column(name = "board_id)
    private Long id;

    @ManyToOne
    @JoinColumn(name = "member_id)
    private Member creator;

    @ManyToOne
    @JoinColumn(name = "member_id)
    private Member modifier;

}

위와 같은 식으로 Entity를 설계했다.
그리고 서버를 실행했을 때 오류가 났다.

2-2. 문제 발생의 원인

원인은 간단했다.
참조를 맺으려는 컬럼이 중복된 컬럼 이기때문에 오류가 발생했던 것이었다.

2-3. 문제 발생을 일으키게 된 이유

제목과 같이 @JoinColumn의 name 속성에 대해 잘 못 알고 있었다.

위와 같은 엔티티를 테이블로 옮겨보자면 다음과 같다.

key 여부 column
PK board_id
... ...
FK member_id
FK member_id

그렇지만 내가 원했던 테이블은 다음과 같다.

key 여부 column
PK board_id
... ...
FK creator
FK modifier

이 때까지 @JoinColumn의 name에는 참조하는 엔티티의 Id 필드(테이블로는 PK 컬럼명)를 넣는 것인 줄 알았는데,
Entity에서 그냥 필드로 다음과 같이 참조를 하면, DB의 테이블에서는 해당 Entity(테이블)의 id를 바라보도록 되어있던 것이었다.

@Getter
@Entity
@NoArgsConstructor(access = AccessLevel.PROTECTED)
public class Board {

    @Id @GeneratedValue(strategy = GenerationType.IDENTITY)
    @Column(name = "board_id)
    private Long id;

    @Column(name = "member_id)
    private Member member;

}

이런 식으로 말이다.

그렇기 때문에 @joinColumn의 name 속성의 값으로는 참조하는 테이블의 PK 명을 넣는 것이 아니라,
(게시판을 예로 들면) 게시판에서 Member의 id를 참조하는 외래 키의 이름을 지정하면 된다.

다시 말해서 Member의 id를 생성자와 수정자를 위해 두 번을 참조하면서, FK의 컬럼명을 creator, modifier로 주고 싶을 때 다음과 같이 하면 된다.

@Getter
@Entity
@NoArgsConstructor(access = AccessLevel.PROTECTED)
public class Board {

    @Id @GeneratedValue(strategy = GenerationType.IDENTITY)
    @Column(name = "board_id)
    private Long id;

    @ManyToOne
    @JoinColumn(name = "creator")
    private Member creator;

    @ManyToOne
    @JoinColumn(name = "modifier")
    private Member modifier;

}

그러면 creator 와 modifier 의 필드가 Board 테이블에서 Member를 참조하는 FK의 컬럼명이 creatormodifier 로 매핑된다.

그럼 다음과 같이 내가 원하는 결과가 나온다.

key 여부 column
PK board_id
... ...
FK creator
FK modifier

3. 요약

결론은 @JoinColumn에서의 name 속성 값은 참조하려는 테이블의 PK 컬럼 명을 넣는 것이 아니라,
참조를 하는 외래 키(FK)의 컬럼명을 지정하는 것이다!!

728x90
Comments