@JoinColumn vs mappedBy

지니·2021년 9월 1일
0

대학생의 일기

목록 보기
10/17

프로젝트 진행 중 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를 가지고 있으므로 연관관계의 주인이 된다.



1. @JoinColumn

@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가 연관관계의 주인이 된다.


+ 추가

오랜만에 헷갈리는 감이 없지 않아 다시 정리하던 중, 잘못된 부분이 있어 수정하러 오게 되었다.


일대다 단방향

  • 일(1)이 연관관계의 주인인 경우를 의미한다. 이는 외래키를 일 쪽에서 관리하겠다는 의미로, 반대편 테이블의 외래키를 관리하는 구조이다.
  • 일대다 단방향 관계를 매핑할 때는 @JoinColumn을 꼭 사용해야 한다.

ex)

@OneToMany(fetch = FetchType.LAZY, cascade = CascadeType.ALL)
@JoinColumn(name = "id")
private List<AnotherObject> anotherObjects;

이는 AnotherObject에서 id라는 이름으로 본인의 PK에 대한 FK를 두고, 이를 본인이 관리하겠다는 뜻이 된다.



2. mappedBy

mappedBy 또한 특정 관계와의 연관관계를 나타낼 때 사용하는데, @ManyToOne과는 달리 연관관계의 주인이 아닌 쪽의 Class 내에서 사용한다.


보통 양방향 연관관계에서 사용한다.

저는 상대 클래스와 연관된 클래스입니다. 관련은 있는데 저에 대한 외래키는 쟤가 갖고있어요. 그러므로 저는 연관관계의 주인이 아니랍니다. mappedBy 붙은 쟤가 연관관계 주인이에요.
(저는 이렇게 기억하고 있습니다.)

예제


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를 가지고 있다.)

3. (추가) @JoinTable

@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<>();
}

@JoinTable의 속성

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

profile
Coding Duck

0개의 댓글