2024.03.21 - [Framework/JPA] - [연관관계 매핑 기초] 단방향 연관관계와 객체와 테이블의 차이
이전 포스팅에서는 단방향에 대해 알아보았다. 이때 객체와 테이블은 패러다임의 차이가 있어 관계를 표현하는 게 다른 것을 확인했다. 테이블은 기본적으로 외래키 조인을 활용한 양방향인데 객체의 필드를 참조하는 방식은 단방향이다.
양방향 연관관계
데이터베이스 테이블처럼 양방향으로 조회하기 위해선 반대쪽 객체의 단방향 참조를 추가하여 양방향 연관관계를 매핑할 수 있다.
회원과 팀은 다대일 관계이다. 반대로 팀과 회원은 일대다 관계이다. 팀쪽에(반대쪽 엔티티)의 회원에 대한 단방향 연관관계를 추가하므로 Team.members라는 List 컬렉션이 추가됨을 알 수 있다.
다대일 관계에서 표현한 것이다. 연관관계의 다중성에 따라 다르게 표현 될 수 있음을 참고하자.
양방향 연관관계 매핑
위 관계를 코드로 풀어보자.
@Entity
public class Member {
@Id
@Colunm(name = "MEMBER_ID")
private String id;
private String username;
//연관관계 매핑
@ManyToOne
@JoinColumn(name = "TEAM_ID")
private Team team;
//연관관계 설정
private void setTeam(Team team) {
this.team = team;
}
//Getter, Setter
}
@Entity
public class Team {
@Id
@Column(name = "TEAM_ID")
private String id;
private String name;
//추가된 부분
@OneToMany(mappedBy = "team")
private List<Member> members = new ArrayList<Member>();
//Getter, Setter
}
기존에 단방향관계과 회원 엔티티의 팀 필드를 만들어 구성하였다. 여기에 위에서 언급한 것처럼 팀입장에서 회원은 일대다 관계이므로 @OneToMany라는 관계를 나타내는 어노테이션과 속성으로 mappedBy를 사용하였다.
mappedBy 속성은 양방향 매핑일 때 사용되며, 반대쪽 매핑의 필드이름의 값을 주면 된다. 여기선 Member 엔티티의 Team team; 필드를 의미한다. 그러므로 team의 값을 주면된다.
이렇게 구성하면 회원 객체에서도 팀을 조회할 수 있고 팀객체에서도 회원을 조회 할 수 있게 된다.
public void test() {
// 설명을 위해 축약된 코드 입니다. 흐름만 확인 부탁드립니다.
...
Team team = em.find(Team.class, "team1");
List<Member> members = team.getMembers(); // 팀객체도 참조를 통해 회원 조회가 가능해진다.
...
}
연관관계의 주인?
@OneToMany라는 어노테이션은 일대다를 직관적으로 표현한 것이니 잘몰라도 이해가 된다. 근데 왜 mappedBy라는 속성이 따라올까?
단방향 포스팅에서도 이야기 했듯이 객체는 양방향 연관관계라는 것이 없다. 서로 다른 단방향 연관관계 2개가 매핑된 것이다. 반면에 데이터베이스의 테이블은 외래키 하나로 두 테이블의 연관관계를 관리한다. 이 말은 한쪽 테이블에 외래키가 걸려있으면 양방향 관계가 된다는 말로 해석된다.
하지만 객체는 양뱡향으로 세팅하기 위해선 서로 다른 객체의 각각 참조 필드를 구성해줘야 한다. 이런 차이로 JPA에서는 두 객체의 연관관계 중 하나를 정해서 테이블의 외래키를 관리해줘야 한다. 이것을 연관관계의 주인이라고 한다.
양방향 매핑 규칙(+mappedBy)
위에서 정의된 내용을 바탕으로 양방향의 규칙을 알아보자.
객체는 테이블과의 패러다음의 차이로 인해 두 개의 참조가 발생되게 된다. 그러므로 객체의 두 관계중 하나를 연관관계의 주인으로 지정해야한다. 참조 필드에 대해서 연관관계의 주인만이 외래 키를 관리할 수 있으며(등록, 수정), 반대로 주인이 아닌 쪽은 읽기만 가능하다.
주인은 mappedby 속성을 사용하면 안된다. mappedBy 직관적으로 보면 알듯이 매핑의 되어진다는 의미이므로 주인이 가실 수 있는 속성이 아니다. 결론적으로 mappedBy 속성은 주인이 아닌 엔티티에서 사용되며 해당 속성의 값은 연관관계의 주인을 지정하는 것을 의미한다.
그럼 누가 주인인것일까?
연관관계의 주인은 테이블에 외래 키가 있는 곳으로 정하면 된다. 위 예제 코드에서는 회원 테이블에 외래키가 존재하므로 Member.team이 주인이 된다.
정리하면 연관관계의 주인만 데이터베이스 연관관계와 매핑되고 외래키 관리를 한다. 주인이 아닌 반대편은 읽기만 가능하고 외래키를 변경하지 못한다.
참고
연관관계 다중성인 다대일, 일대다 관계에서는 향상 다 쪽이 외래키를 가진다. 다 쪽인 @ManyToOne은 항상 연관관계 주인이므로 mappedBy 속성이 존재하지 않는다.
단방향인 경우 항상 외래키가 있는 곳을 매핑하면 된다.
주의할 점으론 연관관계 주인이라는 표현때문에 비즈니스 로직상 더 중요하다고 판단하는 곳을 선택하면 안된다. 단순히 외래키 관리자 정도의 의미 부여만 하면된다.
참고
김영한님의 인프런 강의와 책으로 참조하였습니다.
https://www.inflearn.com/course/ORM-JPA-Basic
자바 ORM 표준 JPA 프로그래밍 - 기본편 | 김영한 - 인프런
김영한 | JPA를 처음 접하거나, 실무에서 JPA를 사용하지만 기본 이론이 부족하신 분들이 JPA의 기본 이론을 탄탄하게 학습해서 초보자도 실무에서 자신있게 JPA를 사용할 수 있습니다., 실무에서도
www.inflearn.com
https://www.yes24.com/Product/Goods/19040233
자바 ORM 표준 JPA 프로그래밍 - 예스24
자바 ORM 표준 JPA는 SQL 작성 없이 객체를 데이터베이스에 직접 저장할 수 있게 도와주고, 객체와 관계형 데이터베이스의 차이도 중간에서 해결해준다. 이 책은 JPA 기초 이론과 핵심 원리, 그리고
www.yes24.com
'Framework > JPA' 카테고리의 다른 글
[JPA] 연관관계 편의 메서드 (0) | 2024.04.29 |
---|---|
[JPA] 객체 관계 매핑에 필요한 @JoinColum 속성 알아보기 (0) | 2024.04.26 |
[연관관계 매핑 기초] 단방향 연관관계와 객체와 테이블의 차이 (0) | 2024.03.21 |
[JPA] 엔티티 매핑 - 기본 키 매핑 (0) | 2024.03.15 |
[JPA] 엔티티 매핑 - 필드와 컬럼 매핑 (0) | 2024.03.14 |