[JPA] physical column name 'parent_id' referred to by multiple logical column names:

bada·2024년 10월 9일

Trouble Shooting

목록 보기
8/10

문제 발생

카테고리를 조회하는 로직을 수정하는 과정에서 셀프 조인으로 재귀 참조를 생각하고 엔티티를 설계했다.

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

    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    private Long id;

    @Column(nullable = false)
    private String name;

    @Column(nullable = false)
    private int sort; //낮을수록 먼저 반환

    @ManyToOne(fetch = FetchType.LAZY)
    @JoinColumn (name = "parent_id")
    private Category parent;

    @OneToMany(mappedBy = "parent", cascade = CascadeType.ALL)
	private List<Category> children = new ArrayList<>();
 
 }

그런데 생각해보니 부모 카테고리의 아이디를 자식이 꼭 가지고 있어야 할 필요가 있을까 하는 의문이 들었다. 왜냐하면 개별 카테고리만 조회할 일이 많지 않고 하위 카테고리를 기준으로 상위 카테고리를 추적하는 방식은 더더욱 아니기 때문에 하위 카테고리가 부모 카테고리 아이디 말고는 전부를 알 필요가 없기 때문이다.

만약 자식 카테고리에서 부모 카테고리의 세부 정보(이름, 정렬 순서 등)가 필요하지 않다면, 부모 카테고리 ID만 저장해도 충분했다. 그래서 양방향 매핑을 단방향으로 수정하는 작업을 진행했다.

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

    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    private Long id;

    @Column(nullable = false)
    private String name;

    @Column(nullable = false)
    private int sort; //낮을수록 먼저 반환

    private Long parentId;

    @OneToMany
    @JoinColumn(name = "parent_id", referencedColumnName = "id")
    private List<Category> children = new ArrayList<>();
 
 }

그런데 자꾸 이런 에러가 뜨는 것.


문제 원인

처음에 나는 기존에 있던 DB상에서의 데이터와 충돌나서 그런가했다. 그래서 DB를 초기화 시키기도 했지만 여전한 문제였다. 생각해보면 DB에 insert될 때 부모카테고리의 ID만 삽입되기 때문에 문제가 없는 부분이긴 했다.

일단 저 에러메시지를 해석해보자면, category 테이블에서 parent_id 컬럼을 참조하고 있는 논리적 컬럼명이 parent_id, parentId 2개가 존재한다는 것.

여기서 논리적 컬럼명이 JPA에서 명시한 컬럼명이고 parent_id는 DB상의 실제 컬럼명을 뜻한다. 그렇다면 parent_id와 parentId 두개를 내가 중복해서 사용한 코드가 있는가? 아니 아무리 봐도 그렇지 않았다.


문제 해결

하위 카테고리가 참조하고 있는 부모 카테고리명은 @JoinColumn의 속성으로 "parent_id"라고 명시를 해주었고, parentId는 명시를 해주지 않았다. 왜냐하면 기본적으로 카멜케이스로 된 JPA 필드명을 DB에서 스네이크케이스로 파싱해주기 때문이다. 그런데 자꾸 parentId라는 것이 언급이 되니 이것을 잘 매핑하도록 명시해주어야겠다고 생각해서 @Column의 이름 속성을 추가주었다.

@Column(name = "parent_id")
private Long parentId;

앱 실행 성공!

profile
하루 세번 목 당기기

0개의 댓글