프로젝트 진행 중 ManyToMany를 불가피하게 사용해야 할 상황이 생겼고 코드를 작성하는 중에 이러한 문제가 발생했었다.
Associations marked as mappedBy must not define database mappings like @JoinTable or @JoinColumn
이처럼 @JoinColumn과 mappedBy를 동시에 사용한게 문제였다.
두 객체 간 연관관계를 나타낼 때 M:N 관계가 아닌 이상 한 객체에서 테이블의 FK를 관리해야 한다.
이때, 연관관계의 주인이란 FK를 가지고 있는 객체를 의미한다.
(수정) 무조건 FK를 가지고 있는 객체가 아닌, FK를 관리하는 객체라고 보는 것이 맞을 것 같다. 일대다 단방향에서 예외가 존재한다.
예시
Team 하나에 여러 Member가 들어갈 수 있다.
Member 한 명은 소속 Team이 한 개다.
Team : Member = 1 : N
이 경우, DB 관점에서 보았을 때 Member가 Team의 id를 FK로 가지게 된다. 즉, Member가 FK를 가지고 있으므로 연관관계의 주인이 된다.
@JoinColumn은 DB 관점으로 보았을 때, 본인이 외래 키를 가지고 있으며 관리하며 상대 Table의 PK(Join할 때 사용)를 명시해주는 역할을 한다.
예시
Member.java@Entity class Member { @Id @GeneratedValue private Long member_id; @ManyToOne @JoinColumn(name="team_id") private Team team; ... }
Team.java@Entity class Team { @Id @GeneratedValue private Long team_id; ... }
이렇게 두면 Member Table의 FK 속성으로 team_id가 생성될 것이다.
연관관계의 주인은FK를 가지고 있는 쪽이다.FK를 관리하는 쪽이다. 즉, @JoinColumn을 쓰는 쪽의 Class가 연관관계의 주인이 된다.
오랜만에 헷갈리는 감이 없지 않아 다시 정리하던 중, 잘못된 부분이 있어 수정하러 오게 되었다.
ex)
@OneToMany(fetch = FetchType.LAZY, cascade = CascadeType.ALL)
@JoinColumn(name = "id")
private List<AnotherObject> anotherObjects;
이는 AnotherObject
에서 id
라는 이름으로 본인의 PK에 대한 FK를 두고, 이를 본인이 관리하겠다는 뜻이 된다.
mappedBy 또한 특정 관계와의 연관관계를 나타낼 때 사용하는데, @ManyToOne과는 달리 연관관계의 주인이 아닌 쪽의 Class 내에서 사용한다.
보통 양방향 연관관계에서 사용한다.
예제
Member.java@Entity class Member { @Id @GeneratedValue private Long member_id; @ManyToOne @JoinColumn(name="team_id") private Team team; ... }
Team.java@Entity class Team { @Id @GeneratedValue private Long team_id; @OneToMany(mappedBy = "team") private List<Member> members = new ArrayList<>(); ... }
Team Class에서 mappedBy="team"을 해줌으로써 Member Class가 Team 객체를 갖고 있고 연관관계의 주인임을 알 수 있다. (DB 관점에서는 Member Table이 FK를 가지고 있다.)
@JoinTable은 두 테이블 간 연관관계를 관리할 때 별도의 테이블을 생성해서 관리하는 경우에 사용한다. 두 객체 간의 관계(DB 관점에서는 두 테이블 간의 관계)가 M:N일 경우 사용한다.
예시 : 인스타그램
인스타그램에서 한 게시물에 해시태그를 여러 개 달 수 있다.
한 해시태그가 여러 게시물에 포함될 수 있다.
게시물과 해시태그 간의 관계는 M : N이다.
Post.java@Entity class Post{ @Id @GeneratedValue Long post_id; @JoinTable(name = "post_tag" , joinColumns = @JoinColumn(name = "post_id" , inverseJoinColumns = @JoinColumn(name = "tag_id")) private Set<Tag> tags = new HashSet<>(); }
name : Join Table 명
joinColumns : 현재 Entity를 참조하는 FK
inverseColumns : 반대방향 Entity를 참조하는 FK
다시 돌아와서!
Associations marked as mappedBy must not define database mappings like @JoinTable or @JoinColumn
이런 오류가 발생한 이유는?
@JoinColumn과 mappedBy를 동시에 사용하였고 이는 본인이 연관관계의 주인이자 연관관계의 주인이 아니라는 것을 의미하게 된다. 이러한 모순으로 인해 에러가 발생했던 것이다.
https://www.baeldung.com/jpa-joincolumn-vs-mappedby
https://incheol-jung.gitbook.io/docs/study/jpa/6