[5단원] 연관관계의 사용

사전정의

@SpringBootTest
@Transactional
public class TestClass {
    
    @Autowired
    EntityManager em;
    
    @BeforeEach
    void setUp() {
        Team team = new Team("team1", "팀1");
        em.persist(team);
        
        Member member1 = new Member("member1", "회원1");
        member1.setTeam(team);
        
        em.persist(member1);
        em.flush();
    }
@AfterEach
    void tearDown() {
        em.flush();
        em.close();
    }

저장

package com.example.springboot3.test;

import com.example.springboot3.entity.Member;
import com.example.springboot3.entity.Team;
import jakarta.persistence.EntityManager;
import org.junit.jupiter.api.Test;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.transaction.annotation.Transactional;

@SpringBootTest
public class TestClass {
    
    @Autowired
    EntityManager em;
    
    @Test
    @Transactional(readOnly = false)
    public void testSave() {
        
        // 팀1 저장
        Team team1 = new Team("team1", "팀1");
        em.persist(team1); // 영속화
        
        // 회원1 저장
        Member member1 = new Member("member1", "회원1");
        member1.setTeam(team1); // 연관관계 설정 member1 -> team1
        em.persist(member1); // 영속화
        
        // 회원2 저장
        Member member2 = new Member("member2", "회원2");
        member2.setTeam(team1); // 연관관계 설정 member2 -> team1
        em.persist(member2); // 영속화
        
        em.flush(); // 영속성 컨텍스트에 있는 내용을 DB에 반영
    }
}

insert into team (name, team_id) values ('팀1', 'team1');

insert into member (team_id, username, member_id) values ('team1', '회원1', 'member1');

insert into member (team_id, username, member_id) values ('team1', '회원2', 'member2');
  • flush 되면서 db에 한번에 쿼리가 날아간다.

조회

객체 그래프 탐색 조회

@Test
void find() {
    Member member = em.find(Member.class, "member1");
    Team team = member.getTeam();// 객체그래프의 탐색
    System.out.println("team = " + team.getName());
}
team = 팀1
  • 객체의 연관관계를 사용하여 조회하는 방법

객체지향쿼리 사용(JPQL)

  • JPQL 을 사용하여 연관관계를 갖는 엔티티를 조회
@Test
void find_JPQL() {
  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();
  for (Member member : resultList) {
      System.out.println("[query] member.username=" + member.getUsername());
  }
select m1_0.member_id,m1_0.team_id,m1_0.username from member m1_0 join team t1_0 on t1_0.team_id=m1_0.team_id where t1_0.name='팀1';
[query] member.username=회원1

수정

void update() {
        // 새로운 팀2
        Team team2 = new Team("team2", "팀2");
        em.persist(team2);
        
        // 회원1에 새로운 팀2 설정
        Member member = em.find(Member.class, "member1");
        member.setTeam(team2);
        em.flush();
    }
insert into team (name, team_id) values ('팀1', 'team1');
update member set team_id='team2', username='회원1' where member_id='member1';
  • em.update() 같은 메서드가 없다.
  • 단순히 엔티티의 값만 변경해두면 트랜잭션을 커밋시에 플러시가 일어난다.
    • 테스트 코드의 경우 별도 트랜잭션 커밋이 발생하지 않음.
    • 그래서 em.flush() 를 호출해줘야 변경감지 기능이 동작함.
  • 변경감지 이후에 DB에 자동적으로 반영함.
  • 연관관계 수정시도 동일함.
    • 참조하는 대상만 변경한다면 나머지는 JPA 가 자동으로 처리

연관관계의 제거

  • 특정 엔티티의 연관관계를 어떻게 제거하는지에 다룬다.
  • Member 엔티티의 setTeam() 메서들을 사용하여 연관된 Team 엔티티와의 연관을 제거가능
@Test
    void relation_remove() {
        Member member1 = em.find(Member.class, "member1");
        member1.setTeam(null);
    }
update member set team_id=NULL, username='회원1' where member_id='member1';
  • 위의 쿼리가 나가게 됩니다.

연관된 엔티티의 삭제

  • 연관된 엔티티를 삭제 전,
  • 해당 엔티티와 연결된 모든 연관관계를 제거해야함
@Test
    void relation_entity_remove() {
        Team team = em.find(Team.class, "team1");
        Member member1 = em.find(Member.class, "member1");
        member1.setTeam(null);
        em.remove(team);
    }
update member set team_id=NULL, username='회원1' where member_id='member1';
delete from team where team_id='team1';

만약 연관된 엔티티를 삭제전에 연관관계를 제거하지 않았다면, 어떤 문제가 발생할까?

  • 외래 키 제약조건 때문에 데이터베이스에서 오류가 발생함.
  • 해당 엔티티를 참조하는 다른 엔티티가 아직 존재하기 때문에 발생


Uploaded by N2T