728x90
반응형
단방향 연관관계
- 단방향 연관관계를 알아본다.
- 객체와 테이블 연관관계의 차이를 이해.
- 객체의 참조와 테이블의 외래 키를 매핑
용어
- 방향(Direction): 단방향, 양방향 존재
- 다중성(Multiplicity): N:1, 1:N, !:1, N:M 이해
- 연관관계 주인(Owner): 객체 양방향 연관관계는 관리 주인이 필요하다.
예제 시나리오
- 회원과 팀이 있다.
- 회원은 하나의 팀에만 소속된다.
- 회원과 팀의 N:1 관계다.
객체와 테이블 연관관계 ERD
- 그림 처럼 객체와 테이블의 연관관계를 만들어 주어야한다.
- 멤버와 팀은 N:1 관계 이고 멤버는 TEAM_ID 를 FK 로 사용하고 있다.
- 아래처럼 멤버만 팀을 참조 한방향으로만 참조하기 때문에 단방향이라고 한다.
데이터 중심의 모델링
연관관계 매핑 없이 데이터 중심으로 모델링예제
보기 쉽게 getter setter 는 생략 했습니다.
Member
@Entity
public class Member {
@Id //PK 설정
@GeneratedValue
@Column(name = "MEMBER_ID")
private Long id;
@Column(name = "name", nullable = false, length = 100)
private String username;
@Column(name = "TEAM_ID")
private Long teamId;
}
Team
package relationmapping;
import javax.persistence.Column;
import javax.persistence.Entity;
import javax.persistence.GeneratedValue;
import javax.persistence.Id;
@Entity
public class Team {
@Id
@GeneratedValue
@Column(name = "TEAM_ID")
private Long id;
private String name;
}
Main
public class RelationMappingEx {
public static void main(String[] args) {
// persistence.xml 의 persistence-unit name="hello" 를 넘긴다.
EntityManagerFactory emf = Persistence.createEntityManagerFactory("hello");
// 매니저를 꺼내온다.
EntityManager em = emf.createEntityManager();
// 트랜잭션 얻어오고 실행한다.
// JPA 는 트랜잭션 안에서 수행되어야 한다.
EntityTransaction tx = em.getTransaction();
tx.begin();
// exception 처리를 위해 try catch 문을 반드시 사용해야된다.
try {
Team team = new Team();
team.setName("TeamA");
em.persist(team);
// 문제1
// setTeamId 는 객체지향 스럽지가 않다.
// setTeam으로 객체를 받아야 객체 지향 스럽다.
Member member = new Member();
member.setUsername("member1");
member.setTeamId(team.getId());
em.persist(member);
// 문제2
// 조회시 가져오는 과정을 두번 거쳐야 된다.
memeber에서 teamId 후 entityManager 에서 Team 을 가져 와야한다.
Member findMember = em.find(Member.class, member.getId());
Team findTeam = em.find(Team.class, findMember.getTeamId());
tx.commit();
} catch (Exception e) {
tx.rollback();
} finally {
em.close();
}
emf.close();
}
}
문제점
문제1: Member에서 Team을 참조하기 위해 Team의 Id 값을 가지고 있다.
- 객체지향 스럽게 설계 하려면 Id 값이 아닌 Team 객체를 가지고 있어야 한다.
문제2: 조회시 무조건 두번의 과정을 거쳐야한다.
- Member를 찾고 Team의 Id 를 가져온다.
- Team 의 Id 로 다시 EntityManager 에서 Team을 가져와야 한다.
테이블과 객체의 갭차이
- 테이블은 외래 키로 조인을 사용해서 연관된 테이블을 찾는다.
- 객체는 참조를 사용해서 연관된 객체를 찾는다.
객체지향 모델링
객체지향 모델링 ERD
- 아래그림은 객체 연관관계를 추가로 표현이된 ERD 이다.
- 객체의 연관관계를 주어 보다 객체스럽게 설계를 할 수 있다.
- Member의 기준으로 봤을때 Member 가 N, Team이 1 N:1 관계이다.
객체지향의 모델링
- 다음 어노테이션으로 맵핑을 해준다.
- @ManyToOne: N:1 을 표현하기 위해 써준다.
- @JoinColumn(name = "TEAM_ID"): 객체 연관관계 에서 Team 과 테이블 연관관계를 맵핑해 주는 역할을 한다
- 위 두개를 이용해 주면 아래 처엄 연관관계 맵핑을 해줄수 있다.
Member
package relationmapping;
import javax.persistence.*;
// 꼭넣어야 한다.
// JPA가 로딩 될때 해당 어노테이션을 보고 인식한다.
@Entity
//@Table(name = "USER") // 테이블명 지정
public class RelationMember {
@Id //PK 설정
@GeneratedValue
@Column(name = "MEMBER_ID")
private Long id;
@Column(name = "name", nullable = false, length = 100)
private String username;
// id 에서 객체로 변환
public Long getId() {
return id;
}
// 객체 모델링
// Member 입장에서 Team 의 연관관계를 볼때
// Member 는 N Team 은 1 이기 때문에
// manytoone 을 써준다.
// 객체 의 FK 인 Team 과 DB의 TEAM_ID 와 맵핑을 해줘야 한다.
// 그럼 DB 와 객체를 맵핑해준것이다
@ManyToOne
@JoinColumn(name = "TEAM_ID")
private Team team;
}
Team
package relationmapping;
import javax.persistence.Column;
import javax.persistence.Entity;
import javax.persistence.GeneratedValue;
import javax.persistence.Id;
@Entity
public class Team {
@Id
@GeneratedValue
@Column(name = "TEAM_ID")
private Long id;
private String name;
}
Main
package relationmapping;
import javax.persistence.EntityManager;
import javax.persistence.EntityManagerFactory;
import javax.persistence.EntityTransaction;
import javax.persistence.Persistence;
public class RelationMappingEx {
public static void main(String[] args) {
// persistence.xml 의 persistence-unit name="hello" 를 넘긴다.
EntityManagerFactory emf = Persistence.createEntityManagerFactory("hello");
// 매니저를 꺼내온다.
EntityManager em = emf.createEntityManager();
// 트랜잭션 얻어오고 실행한다.
// JPA 는 트랜잭션 안에서 수행되어야 한다.
EntityTransaction tx = em.getTransaction();
tx.begin();
// exception 처리를 위해 try catch 문을 반드시 사용해야된다.
try {
Team team = new Team();
team.setName("TeamA");
em.persist(team);
// 객체중심 설계
RelationMember member = new RelationMember();
member.setUsername("member1");
member.setTeam(team);
em.persist(member);
// select 쿼리를 보고 싶을때
em.flush(); // 영속성에있는 데이터를 DB 에 저장
em.clear(); // 영속성 컨텍스트 모두 클리어
// 그래야 아래 에서 셀렉트 쿼리가 나간다.
// 조회시 수정코드
RelationMember findMember = em.find(RelationMember.class, member.getId());
Team findTeam = findMember.getTeam();
System.out.println("username: "+findMember.getUsername());
// 수정
// 변경만 하면 DB 값이 변경된다.
Team newTeam = em.find(Team.class, 100L);
findMember.setTeam(newTeam);
tx.commit();
} catch (Exception e) {
tx.rollback();
} finally {
em.close();
}
emf.close();
}
}
이점
- 객체지향 설계를 할 수 있다.
- 저장할 경우 setTeam 으로 팀객체를 바로 넣어주면된다.
- 조회할 경우 멤버만 찾아서 바로 getTeam을 이용해 Team을 참조할수 있다.
참고: https://www.inflearn.com/course/ORM-JPA-Basic
728x90
반응형
'DataBase > JPA' 카테고리의 다른 글
[JPA] 연관관계 매핑기초3: 양방향 사용시 주의점 (0) | 2021.08.02 |
---|---|
[JPA] 연관관계 매핑기초2: 양방향 연관관계 (0) | 2021.08.02 |
[JPA] 기본매핑 (0) | 2021.08.01 |
[JPA] 기본키 맵핑 (0) | 2021.07.31 |
[JPA] 데이터베이스 스키마 자동 생성 (0) | 2021.07.30 |
댓글