이번에 큐레이션(Curation)과 축제(Festival), 맛집(DeliciousSpot) 간의 관계를 매핑하는 작업을 진행했다.

처음에는 단순히 CurationReqDto.toEntity()로 새 엔티티를 만들어 curation.update()를 호출했다.
// CurationService.java
curation.update(CurationReqDto.toEntity(curationReqDto, findCreator, deliciousSpots, festivals));
// Curation.java
public void update(Curation curation) {
this.type = curation.type;
this.curationDeliciousSpots = curation.curationDeliciousSpots;
this.curationFestivals = curation.curationFestivals;
this.creator = curation.creator;
// ...
}
TransientObjectException: persistent instance references an unsaved transient instance of
'com.culturefinder.songdodongnae.curation.domain.Curation'
(save the transient instance before flushing)
CurationReqDto.toEntity()가 새로운 Curation 엔티티를 생성하기 때문에,
JPA가 보기에 아직 영속화되지 않은(transient) Curation을 중간 테이블(CurationFestival)에서 참조하게 된다.
즉, 새로운 엔티티와 기존 엔티티 간의 관계를 강제로 바꿔 끼우면서 flush 시점에 오류가 발생한 것이다.
큰 아이디어는 "기존 영속 상태의 Curation 엔티티 안에서 연관관계 컬렉션만 수정한다."로 결정했다.
처음에는 CurationDto 객체를 그대로 엔티티의 update() 메서드에 넘기고,
update() 안에서 DTO의 값들을 꺼내 엔티티 필드를 갱신하는 방식으로 접근하려고 했다.
public void update(CurationReqDto dto) {
this.title = dto.getTitle();
this.type = dto.getType();
// ...
}
하지만 이 방식에는 두 가지 문제가 있었다.
결국 DTO가 아니라 DTO에서 꺼낸 값만 넘겨주는 방식으로 변경했다.
// service.java
curation.update(
curationReqDto.getTitle(),
curationReqDto.getDescription(),
curationReqDto.getType(),
curationReqDto.getImageUrl(),
findCreator,
festivals,
deliciousSpots
);
// Curation.java 엔티티
public void update(String title, String description, CurationType type, String imageUrl, Creator creator, List<Festival> festivals, List<DeliciousSpot> deliciousSpots) {
this.type = type;
this.title = title;
// 기존 연관관계 제거
this.curationFestivals.clear();
this.curationDeliciousSpots.clear();
// 새로운 연관관계 매핑
festivals.forEach(this::addFestival);
deliciousSpots.forEach(this::addDeliciousSpot);
}

postman으로 테스트해보면 성공 !