자바 ORM 표준 JPA 프로그래밍 [5-1]

김종하·2022년 7월 24일
0

JPA

목록 보기
7/10

연관관계 매핑 기초

자바 ORM 표준 JPA 프로그래밍 - 김영한
책 내용을 정리한 내용입니다.
챕터5 - 연관관계 매핑 기초
5.1 단방향 연관관계
5.2 연관관계 사용

객체는 참조를 사용해서 관계를 맺고, 테이블은 외래키 를 사용해서 관계를 맺는다.
이런 차이점이 객체 연관관계와 테이블 연관관계 매핑에 어려움을 준다.
따라서 객체의 참조 - 테이블의 외래키를 매핑하는 방법을 목표한다.

  • 방향
    [단방향, 양방향] 이 있다. 회원과 팀이 관계가 있을 때
    회원 -> 팀 또는 팀 -> 회원 둘 중 한쪽만 참조하는 것을 단방향 관계라 하고
    회원 < - > 팀 양 쪽 모두 참조하는 것을 양방향 관계라고 한다.
    "방향" 이라는 객체관계에만 존재하고 테이블 관계는 항상 양방향 이다.

  • 다중성
    [다대일, 일대다, 일대일, 다대다] 다중성이 있다.
    회원과 팀이 관계가 있을 때 여러 회원이 한 팀에 속하므로 회원과 팀은 다대일 관계다.
    반대로 한 팀에 여러 회원이 속할 수 있으므로 팀과 회원은 일대다 관계다

  • 연관관계의 주인
    객체를 양방향 연관관계로 만들면 연관관계의 주인을 정해야 한다.

단방향 연관관계

다대일 단방향 관계

class Member {
 private String id;
 private Team team;
 private String userName;
}

class Team {
 private String id;
 private String name;
}

객체연관관계

Member 객체는 Member.team 을 통해 Team 객체와 연관관계를 맺는다.
Member 에서 Team 을 조회할 수 있지만 Team 에서 Member 는 조회할 수 있다 (단방향 관계)

테이블연관관계

회원 테이블의 TEAM_ID 를 통해 팀-회원의 연관관계를 맺는다.
TEAM 도 TEAM_ID 를 통해 팀에 속한 회원을 조회할 수 있고
MEMBER 도 TEAM_ID 를 통해 회원이 속한 팀을 조회할 수 있다.

차이점

객체는 항상 단방향 연관관계이다.
만약 양방향을 만들고 싶다면 서로가 서로를 참조하도록 2개의 단방향 연관관계를 만들어 주어야 한다.
테이블은 항상 양방향 연관관계이다.

JPA를 통한 관계매핑

@Entity
public class Member {

    @Id
    private Long id;

    private String userName;

    @ManyToOne
    private Team team;
}

@Entity
public class Team {

    @Id
    private Long id;

    private String name;
}

JPA 를 사용하여 엔티트를 설계하면 아래와 같은 테이블 구조를 만들게 된다.

  • @ManyToOne
    다대일 관계라는 매핑 정보.
    연관관계를 매핑할 때 다중성을 나타내는 어노테이션은 필수
    ex) @OneToMany, @OneToOne, @ManyToMany
  • @JoinColumn
    외래키 매핑 정보
    생략 가능하며 생략시 [필드명]_[참조하는 테이블 키의 컬럼명]을 [외래키 컬럼명]으로 한다.

연관관계 사용

저장

@Service
public class TestSave {

    @PersistenceContext
    private EntityManager em;

    @Transactional
    public void save(){
        Team team1 = new Team(1l, "team1");
        em.persist(team1);

        Member member1 = new Member(1l, "user1");
        member1.setTeam(team1);
        em.persist(member1);

        Member member2 = new Member(2l, "user2");
        member2.setTeam(team1);
        em.persist(member2);
    }
}

조회

    @Transactional
    public void find() {
        Member member1 = em.find(Member.class, 1l);
        Team team = member1.getTeam();
        System.out.println(team.getName());
    }
    
    
    @Transactional
    public void find2() {
        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", "team1")
            .getResultList();

        for (Member member : resultList) {
            System.out.println(member.getUserName());
    }
  • 객체 그래프 탐색을 통해 조회할 수 있다.
  • JPQL 을 사용해 조회할 수 있다.

수정

    @Transactional
    public void update() {
        Team team2 = new Team(2l, "team2");
        em.persist(team2);

        Member member1 = em.find(Member.class, 1l);
        member1.setTeam(team2);
    }
  • 불러온 엔티티 값만 변경하면 트랜잭션을 커밋할 때 플러시가 일어나면서 '변경 감지 기능' 이 동작
  • 참조하는 대상만 변경하면 '변경 감지 기능' 이 동작한다.

제거

    @Transactional
    public void delete() {
        Member member1 = em.find(Member.class, 1l);
        member1.setTeam(null);
    }
  • 연관관계를 null 로 설정

삭제

    @Transactional
    public void remove() {
        member1.setTeam(null);
        member2.setTeam(null);
        em.remove(team);
    }
  • 관련된 연관관계를 모두 끊은 후 삭제해야 외래키 제약조건 오류가 나지 않는다.

0개의 댓글