[JPA] 단방향 연관관계
객체의 참조와 테이블의 외래 키를 매핑을 어떻게 할까?
방향 : 테이블과 달리 객체는 참조의 방향이 존재한다.
다중성 : 1:N, N:1, 1:1, N:M의 관계가 있다.
연관관계의 주인 : 객체를 양방향 연관 관계로 만드려면 연관관계의 주인을 정해야한다.
단방향 연관관계
위와 같이 객체의 연관관계를 테이블과 매핑하기 위해서는 아래와 같이 코드를 작성한다.
@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;
}
...
}
@Entity
public class Team {
@Id
@Column(name = "TEAM_ID")
private String id;
private String name;
...
}
객체 연관관계 : 회원 객체의 Member.team 필드 사용
테이블 연관관계 : 회원 테이블의 MEMBER.TEAM_ID 외래 키 컬럼을 사용
@ManyToOne : N:1관계라는 매핑 정보다. 생략 불가능
@JoinColumn(name="TEAM_ID"): 조인 컬럼은 외래 키를 매핑할 때 사용한다. name 속성에는 외래 키 이름을 지정한다. 이 어노테이션은 생략가능
@JoinColumn
외래 키를 매핑할 때 사용한다.
name : 매핑할 외래 키 이름 (기본 값은 필드명 + _ + 참조하는 테이블의 기본 키 컬럼명)
referencedColumnName : 외래 키가 참조하는 대상 테이블의 컬럼명 (참조하는 테이블의 기본 키 컬럼명)
foreignKey(DDL) : 외래 키 제약조건을 직접 지정 할 수 있음. 테이블을 생성할 때만 사용된다.
unique, nullable, insertable, updatable, columnDefinition, table : @Column 속성과 같음
@ManyToOne
optional : false로 설정하면 연관된 엔티티가 항상 있어야 한다. 기본 값(true)
fetch : 글로벌 패치 전략 (기본 값 ManyToOne = FetchType.EAGER @OneToMany=FetchType.LAZY)
cascade : 영속성 전이 기능을 사용한다.
연관관계 사용
저장
public void testSave(){
//팀 저장
Team team1 = new Team("team1", "팀1");
em.persist(team1);
//회원 저장
Member member1 = new Member("member1", "회원1");
member1.setTeam(team1); //연관관계설정
em.persist(member1);
//회원2 저장
Member member2 = new Member("member2", "회원2");
member2.setTeam(team1); //연관관계 설정
em.persist(memeber2)
}
* JPA에서 엔티티를 저장할 떄 연관된 모든 엔티티는 영속 상태여야 한다.
조회
객체 그래프 탐색
Member member = em.find(Member.class, "member1");
Team team = Member.getTeam(); //객체 그래프 탐색
객체를 통해 연관된 엔티티를 조회하는 것 이다.
객체지향 쿼리 사용
private static void queryLogicJoin(EntitiyManger em){
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");
.getResultList();
}
JPQL을 쿼리를 보면 m.team을 통해서 member와 team을 조인했다. :teamName같이 :로 시작하는 것은 파라미터를 바인딩 받는 문법이다.
수정
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);
}
update에는 따로 메서드가 존재하지 않고 엔티티가 수정되면 트랜잭션이 커밋할때 플러시가 일어나서 변경 감지를 한다.
연관관계 제거
private static void deleteRelation(EntityManager em) {
Member member = em.find(Member.class, "member1");
member.setTeam(null);
}
연관된 엔티티 삭제
member1.setTeam(null);
member2.setTeam(null);
em.remove(team)
연관된 엔티티를 삭제하려면 기존의 연관관계를 먼저 제거하고 삭제해야 한다. 그렇지 않으면 외래키 제약조건으로 데이터베이스에서 오류가 발생한다.