반응형
결론부터 말하자면 Spring Data Jpa의 JpaRepository를 사용할 때 발생하는 문제다.
처음 만난 문제는 PK 값을 가지고 있는 객체가 데이터베이스에는 존재하지 않을 때, 이 객체와 연관관계를 맺고 save 메서드로 영속화를 시도하면 연관관계를 맺고 있는 객체가 데이터베이스에 존재하지 않기 때문에 EntityNotFoundException이 발생한다.
두 번째 문제는 PK 값을 가지고 있는 객체를 JpaRepository.save 메서드로 영속화 했을 때, 이 객체는 영속화가 되지 않기 때문에 발생하는 문제다.
문제 코드
테스트 코드용 더미 데이터를 생성하는 클래스를 아래와 같이 만들었다.
public class TestDataFactory {
public static Long userId = 1L;
public static Long boardId = 1L;
public static Long columnId = 1L;
public static User getUser() {
return User.builder()
.id(userId++)
.build();
}
public static Board getBoard() {
String name = RandomString.make(10);
String description = RandomString.make(10);
return Board.builder()
.id(boardId++)
.name(name)
.description(description)
.backgroundColor("#FFFFFF")
.build();
}
public static Columns getColumn() {
return Columns.builder()
.id(columnId++)
.build();
}
}
그리고 아래의 테스트 코드를 작성했다.
문제 1번
save 메서드를 호출할 때, 예외가 발생한다.
@Test
@Transactional
void findAllByUserId() {
// given
User user = TestDataFactory.getUser();
Long userId = user.getId();
Board board = TestDataFactory.getBoard();
Board board1 = TestDataFactory.getBoard();
Board board2 = TestDataFactory.getBoard();
user.addBoard(board);
user.addBoard(board1);
user.addBoard(board2);
userRepository.save(user);
}
1번 해결
먼저 저장한 후에 연관관계를 설정해주자. 다른 방법으로는 Cascade를 설정하면 같이 저장하게 되므로 해결할 수 있다.
@Test
@Transactional
void findAllByUserId() {
// given
User user = TestDataFactory.getUser();
Long userId = user.getId();
Board board = TestDataFactory.getBoard();
Board board1 = TestDataFactory.getBoard();
Board board2 = TestDataFactory.getBoard();
userRepository.save(user);
user.addBoard(board);
user.addBoard(board1);
user.addBoard(board2);
}
문제 2번
user를 save 메서드를 호출해서 영속화 한 후에 addBoard 메서드로 user와 board의 연관관계를 설정한다. 이때 문제가 발생한다.
@Test
@Transactional
void findAllByUserId() {
// given
User user = TestDataFactory.getUser();
Long userId = user.getId();
Board board = TestDataFactory.getBoard();
Board board1 = TestDataFactory.getBoard();
Board board2 = TestDataFactory.getBoard();
userRepository.save(user);
user.addBoard(board);
user.addBoard(board1);
user.addBoard(board2);
boardRepository.save(board);
boardRepository.save(board1);
boardRepository.save(board2);
// when
List<Board> boards = boardRepository.findAllByUserId(userId);
// then
assertThat(boards).hasSize(3);
}
2번 해결
PK 값을 가지고 있는 객체는 save 메서드를 호출했을 때 내부적으로 entitymanager가 persist가 아닌 merge 메서드를 사용하기 때문에 save 메서드를 호출해도 메서드에 전달한 객체는 파라미터일 뿐, 영속화가 되지 않는다. 따라서 영속화된 객체와 연관관계를 설정해야 한다.
@Test
@Transactional
void findAllByUserId() {
// given
User user = TestDataFactory.getUser();
Long userId = user.getId();
Board board = TestDataFactory.getBoard();
Board board1 = TestDataFactory.getBoard();
Board board2 = TestDataFactory.getBoard();
User save = userRepository.save(user);
save.addBoard(board);
save.addBoard(board1);
save.addBoard(board2);
boardRepository.save(board);
boardRepository.save(board1);
boardRepository.save(board2);
// when
List<Board> boards = boardRepository.findAllByUserId(userId);
// then
assertThat(boards).hasSize(3);
}
반응형
'Tool > Spring' 카테고리의 다른 글
[Spring] Spring Data JPA의 쿼리 메서드로 정렬 조건 여러 개 + 페이지네이션 조회하기 (0) | 2023.12.20 |
---|---|
[Spring] Spring boot와 redis로 회원가입 이메일 인증기능 만들기 (0) | 2023.12.18 |
[Spring] 커스텀 어노테이션으로 DTO 유효성 검사하기 (0) | 2023.12.14 |
[Spring boot] 외부 파일 저장소를 사용할 때 트랜잭션은 어떻게 관리해야 할까? (with. AWS S3) (2) | 2023.12.11 |
[Spring boot] controller layer 테스트 코드 작성하기 (0) | 2023.12.04 |