자바 ORM 표준 JPA 프로그래밍 - 단방향 연관관계, 연관관계 사용
05. 연관관계 매핑 기초
이 장의 목표는 객체의 참조와 테이블의 외래 키를 매핑하는 것이다.
- 객체 : 참조(주소)를 사용해서 관계를 맺음
- 테이블 : 외래 키를 사용해서 관계를 맺음
- 방향(Direction) : [단방향, 양방향]
ex) 회원 & 팀과의 관계
단방향 관계 : 회원 -> 팀 or 팀 -> 회원
양방향 관계 : 회원 -> 팀 and 팀 -> 회원
-> 방향은 객체관계에만 존재, 테이블 관계는 항상 양방향!
- 다중성(Multiplicity) : [다대일(N:1), 일대다(1:N), 일대일(1:1), 다대다(N:M)]
- 연관관계의 주인(Owner) : 객체를 양방향 연관관계로 만들면 연관관계의 주인을 정해야 함.
5.1 단방향 연관관계
회원과 팀의 관계를 통해 다대일(N:1) 단방향 관계를 알아보자
이 장의 목표는 객체의 참조와 테이블의 외래 키를 매핑하는 것이다.
- 객체 : 참조(주소)를 사용해서 관계를 맺음
- 테이블 : 외래 키를 사용해서 관계를 맺음
ex) 회원 & 팀과의 관계
단방향 관계 : 회원 -> 팀 or 팀 -> 회원
양방향 관계 : 회원 -> 팀 and 팀 -> 회원
-> 방향은 객체관계에만 존재, 테이블 관계는 항상 양방향!
회원과 팀의 관계를 통해 다대일(N:1) 단방향 관계를 알아보자
- 회원과 팀이 있다.
- 회원은 하나의 팀에만 소속될 수 있다.
- 회원과 팀은 다대일 관계이다.
-
객체 연관관계
- 회원 객체는 Member.team 필드(멤버변수)로 팀 객체와 연관관계를 맺음.
- 단방향 관계.
회원은 Member.team 필드를 통해 팀을 알 수 있지만, 반대로 팀은 회원을 알 수 없음.
ex) member.getTeam()
-
테이블 연관관계
- 회원 테이블은 TEAM_ID 외래 키로 팀 테이블과 연관관계.
- 양방향 관계.
회원 테이블의 TEAM_ID 외래 키를 통해 회원과 팀을 조인할 수 있고, 반대로 팀과 회원도 조인 가능.
ex) 회원과 팀 조인하는 SQL
ex) 팀과 회원을 조인하는 SQL
-
객체 연관관계와 테이블 연관관계의 가장 큰 차이
- 참조를 통한 연관관계는 언제나 단방향.
- 객체간에 연관관계를 양방향으로 만들고 싶으면 반대쪽에도 필드를 추가해 참조를 보관해야함
-> 연관관계를 하나 더 만드는 것.
-> 양방향 관계가 아닌 서로 다른 단방향 관계 2개
ex) 단방향 연관관계
ex) 양방향 연관관계
-
객체 연관관계 vs 테이블 연관관계 정리
- 객체 : 참조(주소)로 연관관계를 맺음. 참조를 사용해 데이터 조회
- 테이블 : 외래 키로 연관관계를 맺음. 조인(JOIN)을 통해 테이터 조회
5.1.1 순수한 객체 연관관계
// 예제 5.1) JPA를 사용하지 않은 순수한 회원과 팀 클래스 코드
public class Member {
private String id;
private String username;
private Team team; // 팀의 참조를 보관
public void setTeam(Team team) {
this.team = team;
}
// Getter, Setter ...
}
public class Team {
private String id;
private String name;
// Getter, Setter ...
}
// 예제 5.2) 회원1과 회원2를 팀1에 소속시키는 코드
public static void main(String[] args) {
// 생성자(id, 이름)
Member member1 = new Member("member1", "회원1");
Member member2 = new Member("member2", "회원2");
Team team1 = new Team("team1", "팀1");
member1.setTeam(team1);
member2.setTeam(team1);
Team findTeam = member1.getTeam();
}
- 객체 그래프 탐색 : 객체는 참조(member1.getTeam())를 사용하여 연관관계를 탐색할 수 있음.
5.1.2 테이블 연관관계
데이터베이스 테이블의 회원과 팀의 관계를 살펴보자
회원 테이블의 TEAM_ID에 외래 키 제약 조건 설정
회원1과 회원2를 팀1에 소속 시킴
회원1이 소속퇸 팀 조회
- 조인 : 데이터베이스는 외래 키를 사용하여 연관관계를 탐색할 수 있음.
5.1.3 객체 관계 매핑
JPA를 사용하여 객체와 테이블을 매핑해보자
- 객체 연관관계 : 회원 객체의 Member.team 필드 사용
- 테이블 연관관계 : 회원 테이블의 MEMBER.TEAM_ID 외래 키 컬럼을 사용
-> 연관관계 매핑 : Member.team과 MEMBER.TEAM_ID를 매핑하는 것
// 예제 5.4) 매핑한 회원 엔티티
@Entity
public class Member {
@Id
@Column(name = "MEMBER_ID")
private String id;
private String username;
// 연관관계 매핑
@ManyToOne
@JoinColumn(name="TEAM_ID")
private Team team;
// 연관관계 설정
public void setTeam(Team team) {
this.team = team;
}
// Getter, Setter ...
}
// 예제 5.5) 매핑한 팀 엔티티
@Entity
public class Team {
@Id
@Column(name = "TEAM_ID")
private String id;
private String name;
// Getter, Setter ...
}
이제 위 매핑 코드에 작성한 연관관계 매핑 어노테이션에 대해 알아보자!
5.1.4 @JoinColumn
- 외래 키를 매핑할 때 사용.
- name 속성에는 매핑할 외래 키 이름을 지정.
ex) 회원과 팀 테이블은 TEAM_ID 외래 키로 연관관계를 맺어 @JoinColumn(name="TEAM_ID")을 지정하면 됨. - 생략 가능
참고) @JoinColumn 생략
- 생락하면, 외래 키를 찾을 때 기본 전략을 사용
- 기본 전략 : 필드명 + _ + 참조하는 테이블의 컬럼명
ex)
@ManyToOne
private Team team;
: 필드명(team) + _(밑줄) + 참조하는 테이블의 컬럼명(TEAM_ID)
= team_TEAM_ID 외래 키를 사용
5.1.5 @ManyToOne
- 다대일(N:1) 관계라는 매핑 정보.
- 연관관계 매핑 시, 다중성을 나타내는 어노테이션 필수로 사용
ex) 회원과 팀은 다대일 관계
// targetEntity 속성의 사용 예
@OneToMany
private List<Member> members; // 제네릭으로 타입정보 알 수 있음
@OneToMany(targetEntity=Member.class)
private List members; // 제네릭이 없으면 타입 정보 알 수 없음
참고) 일대일(@OneToOne)관계
- 단방향 관계 매핑할 때 다대일, 일대일 둘 중 어떤 것을
사용할지는 반대편 관계에 달려 있음.
- 반대편이 일대다 관계 -> 다대일
일대일 관계 -> 일대일
5.2 연관관계 사용
연관관계를 등록, 수정, 삭제, 조회 예제를 통해 연관관계를 어떻게 사용하는지 알아보자!
5.2.1 저장
// 예제 5.6) 회원과 팀을 저장하는 코드
public void testSave() {
// 팀1 저장
Team team1 = new Team("team1", "팀1");
em.persist(team1);
// 회원1 저장
/**
JPA는 참조한 팀의 식별자(Team.id)를
외래 키로 사용하여 적절한 등록 쿼리 생성함.
**/
Member member1 = new Member("member1", "회원1");
member1.setTeam(team1); // 연관관계 설정 member1 -> team1
em.persist(member1);
// 회원2 저장
Member2 member2 = new Member("member2", "회원2");
member2.setTeam(team1); // 연관관계 설정 member2 -> team1
em.persist(member2);
}
* 주의 *
JPA에서 엔티티 저장할 때는 연관된 모든 엔티티 영속상태 여야 함.
- 이때 실행된 SQL : 회원 테이블의 외래 키 값으로 참조한 팀의 식별자 값인 team1 입력됨
5.2.2 조회
- 객체 그래프 탐색(객체 연관관계를 사용한 조회)
Member member = em.find(Member.class, "member1");
Team team = member.getTeam(); // 객체 그래프 탐색
System.out.println("팀 이름 = " + team.getTeam());
// 출력결과 : 팀 이름 = 팀1
- 객체지향 쿼리 이용(JPQL)
- JPQL도 조인을 지원하기 때문에 연관된 테이블을 조인해서 검색조건을 사용하여 조회한다.
// 예제 5.7) 팀1에 소속된 모든 회원을 조회하는 JPQL 조인 검색
private static void queryLoginJoin(EntityManager em) {
// 회원이 팀과 관계를 가지고 있는 필드(m.team)를 통해 Member와 Team 조인
// t.name을 검색조건으로 사용해 팀1에 속한 회원만 검색
String jpql = "select m from Member m join m.team t where " +
"t.name=:teamName"; // :로 시작하는 것은 파라미터를 바인딩받는 문법
List<Member> resultList = em.createQuery(jpql, Member.class)
.setParameter("teamName", "팀1");
.getResultLit();
for (Member member : resultList) {
System.out.println("[query] member.username=" +
member.getUsername());
)
}
// 결과 : [query] member.username=회원1
// 결과 : [query] member.username=회원2
- 이때 실행된 SQL
: JPQL은 객체(엔티티)를 대상으로 하고 SQL보다 간결.
5.2.3 수정
// 예제 5.8) 팀1 소속이던 회원을 새로운 팀2에 소속하도록 수정
private static void updateRelation(EntityManager em) {
// 새로운 팀2
Team team2 = new Team("team2", "팀2");
em.persist(team2);
// 회원1에 새로운 팀2 설정
Member member = em.find(Member.class, "member1);
member.setTeam(team2);
}
- 실행되는 SQL
: 단순히 불러온 엔티티 값만 변경하면 트랜잭션 커밋 시에 플러시가 일어나면서 변경 감지 기능이 작동하여 변경사항을 데이터베이스에 자동으로 반영한다.
= 연관관계를 수정할 때
(참조하는 대상만 변경하면 나머지는 JPA가 자동으로 처리)
5.2.4 연관관계 제거
// 예제 5.9) 회원1을 팀에 소속하지 않도록 변경
private static void deleteRelation(EntityManager em) {
Member member1 = em.find(Member.dclass, "member1");
member1.setTeam(null); // 연관관계 제거
- 실행되는 SQL
5.2.5 연관된 엔티티 삭제
- 기존에 있던 연관관계를 먼저 제거하고 삭제해야함
- 그렇지 않으면, 외래 키 제약조건 때문에 DB에서 오류 발생.
- 팀1에는 회원1과 회원2가 소속되어 있음.
- 팀1 삭제하려면 연관관계를 먼저 끊어야함.
출처 : 자바 ORM 표준 JPA 프로그래밍 책
Author And Source
이 문제에 관하여(자바 ORM 표준 JPA 프로그래밍 - 단방향 연관관계, 연관관계 사용), 우리는 이곳에서 더 많은 자료를 발견하고 링크를 클릭하여 보았다 https://velog.io/@hyehyes/자바-ORM-표준-JPA-프로그래밍-단방향-연관관계-연관관계-사용저자 귀속: 원작자 정보가 원작자 URL에 포함되어 있으며 저작권은 원작자 소유입니다.
우수한 개발자 콘텐츠 발견에 전념 (Collection and Share based on the CC Protocol.)