JPA

[JPA] 단방향 연관관계

제리 . 2020. 11. 20. 18:19

객체의 참조와 테이블의 외래 키를 매핑을 어떻게 할까?

 

방향 : 테이블과 달리 객체는 참조의 방향이 존재한다. 

다중성 : 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)

연관된 엔티티를 삭제하려면 기존의 연관관계를 먼저 제거하고 삭제해야 한다. 그렇지 않으면 외래키 제약조건으로 데이터베이스에서 오류가 발생한다.