안녕하세요. 개발자 Jindory입니다.
오늘은 JPA 연관관계 매핑에 대해서 알아보는 글을 작성해보고자 합니다.
JPA 연관관계 매핑
엔티티들은 대부분 다른 엔티티들과 연관관계를 가지고 있다. 예를 들어 대학생과 대학교 강의 간에도 A과목을 수강하는 학생의 관계, 학생이 수강한 과목과의 관계 서로를 가지고 있다. DB에서는 이런 연관관계를 맺고자 외래키(Foreign Key)를 맺어서 서로의 연관관계를 맺는다. 따라서 엔티티들 간에 관계를 매핑해 주는것을 연관관계 매핑이라고 하며, JPA에서 어떻게 연관관계 매핑을 하는지에 대해서 알아보고자 한다.
연관관계는 방향,다중성, 연관관계의 주인으로 크게 3가지로 나눠볼 수 있으며 아래와 같이 분류 할 수 있다.
- 방향
- 단방향 : 하나의 엔티티에서 다른 엔티티를 일방향적으로 관계를 맺는것을 의미한다.
- 양방향 : 관계를 가진 엔티티가 서로 관계를 맺어서 서로 관계를 맺은 엔티티와의 관계를 알 수 있는 관계를 의미한다.
- 다중성
- 다대일(N:1) : 다양한 객체가 한 객체와 관계를 맺음을 의미한다.
ex) 다양한 동식물이 한 생태계에 살고 있다. - 일대다(1:N) : 하나의 객체가 다양한 객체와 관계를 맺음을 의미한다.
ex) 한 생태계에 다양한 동식물이 살고 있다. - 일대일(1:1) : 한 객체가 다른 한 객체와 관기를 맺음을 의미한다.
ex) A 학생이 B 학교를 다닌다. - 다대다(N:M) : 다양한 객체가 다양한 객체와 관계를 맺음을 의미한다.
ex) 화학과 학생들은 각기 다른 과목을 수강하고 있습니다.
- 다대일(N:1) : 다양한 객체가 한 객체와 관계를 맺음을 의미한다.
- 연관관계 주인(Owner) : 객체를 양방향 연관관계로 만들려면 한 객체가 다른 객체의 주인의 역할을 가져야 한다.
단방향 매핑
하나의 객체에서 다른 객체를 조회할 수 있는 구조로 만드는 것이다.
위 그림은 Member 객체 안에 Team 객체를 넣음으로써 Member에서 Team객체를 조회 할 수 있다.
(단, Team객체에서 Team에 해당하는 Member 객체는 조회할 수 없다.)
이때 Memeber는 하나의 Team을 가질 수 있으며, Team은 다양한 Member를 가질 수 있는 일대다/다대일 관계이다.
@Entity
public class Member{
@Id @GeneratedValue
private Long id;
@Column(name="USERNAME")
private String name;
private int age;
@ManyToOne
@JoinColumn(name="TEAM_ID")
private Team team;
}
위와 같이 Member 객체를 정의함으로써 Memeber에서 Team의 관계를 갖는 단방향 매핑관계가 맺어진다.
위와 같이 단방향 연관관계를 맺음으로써 아래와 같이 연관관계를 저장할 수 있다.
// 팀 저장
Team team = new Team();
team.setName("Team A");
em.persist(team);
// 회원 저장
Member member = new Member();
member.setName("member1");
member.setTeam(team); // 단방향 연관관계 설정, 참조 저장
em.persist(member);
이렇게 저장한 Member에서 Team을 조회하려면 아래와 같이 조회하면 된다.
// 조회
Member findMember = em.find(Member.class, member.getId());
// 참조를 사용해서 연관관계 조회
Team findTeam = findMember.getTeam();
연관관계 수정은 아래와 같이 객체값을 변경하면 수정이 된다.
// 새로운 팀B
Team teamB = new Team();
teamB.setName("TeamB");
em.persist(teamB);
// 회원1에 새로운 팀B 설정
member.setTeam(teamB);
양방향 매핑
Member에서도 Team의 정보를 조회하고 Team에서도 Team과 연관된 Member의 정보를 알고 싶다면 Memeber와 Team의 양방향 매핑을 통해 관계를 맺어주어야 한다. DB에서는 테이블간 관계가 맺어져 있다면 양방향 조회가 되지만 Java 객체에서 양방향 조회가 되려면 각각의 객체에 연관될 수 있는 정보를 설정해주어야 한다.
[ Member 객체 ]
@Entity
public class Member{
@Id @GeneratedValue
private Long id;
@Column(name="USERNAME")
private String name;
private int age;
@ManyToOne
@JoinColumn(name="TEAM_ID")
private Team team;
}
[ Team 객체 ]
@Entity
public class Team {
@Id @GeneratedValue
private Long id;
private String name;
@OneToMany(mappedBy = "team)
List<Member> members = new ArrayList<Member>();
}
이렇게 양방향 매핑을 한 객체에서는 Member와 Team 어디에서도 연관된 객체를 조회할 수 있다.
// 조회
Team findTeam = em.find(Team.class, team.getId());
int memberSize = findTeam.getMembers().size(); // 역방향 조회
단 양방향 관계를 맺을때는 연관관계 객체 사이에서 주인관계를 정의해야한다.
DB에서 Member테이블과 Team테이블이 아래와 같은 관계를 가질때 TEAM_ID를 변경했을때, MEMBER의 TEAM_ID는 자동으로 변경되어야 하지만, MEMBER에서 TEAM_ID를 변경할 수 없다.
하지만 객채에서 객체에서의 양방향 관계는 사실 양방향 관계가 아니라 서로 다른 단방향 관계 2개를 만든것이므로 각자의 객체에서 다른 객체의 값을 변경할 수 있어서 데이터 관리에 큰 문제가 생긴다.
따라서 객체의 관계중에서 주인(Owner)를 지정하여 한 객체에서만 다른 객체의 참조를 변경 할 수 있도록 만들어줘야 한다.
연관관계의 주인(Onwer)
- 객체의 두 관계중 하나의 연관관계의 주인으로 지정
- 연관관계의 주인만이 외래키를 관리(등록,수정)
- 주인이 아닌쪽은 읽기만 가능
- 주인은 mappedBy 속성을 사용하지 않는다.
- 주인이 아니면 mappedBy 속성으로 주인을 지정한다.
그렇다면 어떤 객체를 주인으로 정해야하는가?
=> 두 객체 중 외래키를 가진 객체를 주인으로 정한다.
주인이 아닌 객체에서 주인의 값을 셋팅하는 경우 아래와 같이 값이 입력되지 않는 상황이 벌어진다.
Team team = new Team();
team.setName("TeamA");
em.persist(team);
Member member = new Member();
member.setName("member1");
// 역방향(주인이 아닌 방향)만 연관관계 설정
team.getMembers().add(member);
em.persist(member);
따라서 양방향 매핑시 연관관계의 주인에 값을 입력해야한다.
(순수한 객체 관계를 고려하면 항상 양쪽 다 값을 입력해야 한다.)
Team team = new Team();
team.setName("TeamA");
em.persist(team);
Member member = new Member();
member.setName("member1");
team.getMembers().add(member);
// 연관관계의 주인에 값을 설정
member.setTeam(team);
em.persist(member);
연관관계 매핑과 관련된 어노테이션은 아래와 같이 있다.
- 다대일(@ManyToOne)
- 일대다(@OneToMany)
- 일대일(@OneToOne)
- 다대다(@ManyToMany)
- @JoinColumn, @JoinTable
- @Inheritance
- @DiscriminatorColumn
- @DiscriminatorValue
- @MappedSuperclass(매핑 속성만 상속)
복합키 어노테이션은 아래와 같이 있다.
- @IdClass
- @EmbeddedId
- @Embeddable
- @MapsId
이렇게 JPA 연관관계 매핑에 대해서 알아봤습니다.
혹시라도 정정할 내용이나 추가적으로 필요하신 정보가 있다면 댓글 남겨주시면 감사하겠습니다.
오늘도 Jindory 블로그에 방문해주셔서 감사합니다.
[참조]
https://www.youtube.com/watch?v=bEtTpCviSc4&list=PL9mhQYIlKEhfpMVndI23RwWTL9-VL-B7U&index=4
'개발 > JPA' 카테고리의 다른 글
[JPA] JPA 관련 application.properties 설정 (0) | 2022.04.27 |
---|---|
[JPA] 객체지향 쿼리 (0) | 2022.02.22 |
[JPA] JPA 영속성 컨텍스트 (0) | 2022.02.22 |
[JPA] JPA 기초 (0) | 2022.02.16 |
[JPA] JPA란 무엇일까? (0) | 2022.02.16 |