오늘의 회고록은 데이터테이블을 설계할때 jpa로 테이블간 연관관계에 대해 정리해보려합니다. 과제를 진행하며 게시판의 게시글과 각각의 게시글에 덧글을 관계를 설정하기 위해 찾아보다 이렇게 정리하게 되었습니다.
연관관계를 맵핑할 때 고려해야 하는 3가지
연관관계에는 다음과 같은 다중성이 있습니다.
- 일대일 OneToOne ( 1 : 1)
- 일대다 OneToMany ( 1 : N )
- 다대일 ManyToOne ( N : 1 )
- 다대다 ManyToMany ( N : N )
- 단방향
- 양방향
객체 양방향 연관관계는 관리가 필요하다. 다대다
package study.datajpa.dto;
import javax.persistence.Column;
import javax.persistence.Entity;
import javax.persistence.GeneratedValue;
import javax.persistence.Id;
/* 회원(Member) 엔티티*/
@Entity
public class Member {
@Id @GeneratedValue
private Long id;
@Column(name = "USERNAME")
private String name;
@Column(name = "TEAM_ID")
private Long teamId;
}
/* 팀(Team) 엔티티 */
@Entity
public class Team{
@Id @GeneratedValue
private Long id;
private String name;
}
무엇이 문제인가? DB에 저장 & 조회
package hellojpa;
import javax.persistence.EntityManager;
import javax.persistence.EntityManagerFactory;
import javax.persistence.EntityTransaction;
import javax.persistence.Persistence;
public class JpaMain {
public static void main(String[] args) {
EntityManagerFactory emf = Persistence.createEntityManagerFactory("hello");
EntityManager em = emf.createEntityManager();
EntityTransaction tx = em.getTransaction();
tx.begin();
try{
/* 팀과 멤버를 저장하는 로직 */
Team team = new Team();
team.setName("teamA");
em.persist(team);
Member member = new Member();
member.setName("mamber1");
member.setTeamId(team.getId());
em.persist(member);
tx.commit();
}catch(Exception e ){
tx.rollback();
}finally {
em.close();
}
}
}
-> 외래키 식별자를 직접 다루고 있어 조회할 때 해당 외래키를 가지고 조인 쿼리를 직접 짜야한다.
-> 외래키를 직접 관리하는 테이블에 맞춘 객체 모델링은 객체간의 협력관계를 만들 수 없고, 객체가 참조를 통해 연관객체를 찾는 다는 사상을 적용할 수 없다.
package hellojpa;
import javax.persistence.*;
/* 회원(Member) 엔티티*/
@Entity
public class Member {
@Id @GeneratedValue
private Long id;
@Column(name = "USERNAME")
private String name;
@ManyToOne
@JoinColumn(name = "team_id")
private Team team;
... getter, setter
}
@ManyToOne
@JoinColumn
을 통해 멤버(Member)에서 팀(Team)을 참조하도록 했다. try{
Team team = new Team();
team.setName("teamA");
em.persist(team);
Member member = new Member();
member.setName("mamber1");
member.setTeam(team);
em.persist(member);
em.flush();
em.clear();
Member findMember = em.find(Member.class, member.getId());
Team findTeam = member.getTeam();
tx.commit();
}catch(Exception e ){
tx.rollback();
}finally {
em.close();
}
@Entity
public class Team{
...
@OneToMany(mappedBy = "team")
private List<Member> members = new ArrayList<>();
...
}
menbers
를 확인하는 코드Member findMember = em.find(Member.class, member.getId());
List<Member> members = findMember.getTeam().getMembers();
for (Member member1 : members) {
System.out.println("member1.getName() = " + member1.getName()); // member1.getName() = mamber1
}
A -> B(a.getB())
B -> A(b.getA())
연관관계의 주인(Owner) -> 양방향 매핑 규칙