현재 Post 엔티티와 PostHashtag 엔티티는 1:N 양방향 매핑이 되어있고
Hashtag 엔티티도 PostHashtag와 1:N 양방향 매핑이 되어있다.
Post
@OneToMany(mappedBy = "post", cascade = CascadeType.ALL)
private final Set<PostHashtag> postHashtags = new LinkedHashSet<>();
Posthashtag
@Setter
@ManyToOne(optional = false)
@JoinColumn(name = "postId")
private Post post;
@Setter
@ManyToOne(optional = false)
@JoinColumn(name = "hashtagId")
private Hashtag hashtag;
@JoinColum`을 외래키의 이름을 지정하는 단순한 역할로 알고 있었어서 아래의 메서드를 작성했었다.
private Page<PostResponse> toResponses(Page<Post> posts, Pageable pageable) {
List<PostResponse> postResponses = posts.stream()
.map(post -> {
return PostResponse.from(post, getHashtagNames(post));
})
.toList();
return new PageImpl<>(postResponses, pageable, postResponses.size());
}
private List<String> getHashtagNames(Post post) {
return postHashtagRepository.findAllByPost_Id(post.getId())
.stream()
.map(postHashtag -> {
return hashtagRepository.getReferenceById(postHashtag.getHashtag().getId()).getHashtagName();
})
.toList();
}
두 개의 메서드는 Post를 조회할 때 Hashtag 도 같이 조회하는 메서드이다. Post와 Hashtag가 PostHashtag를 통해 연결되기 때문에 postHashtagRepository와 hashtagRepository를 모두 조회한다.
하지만 @JoinColum을 설정해두면 @OneToMany 양방향 관계에서 one 쪽에서 조회할 때, JPA가 알아서 many 쪽의 데이터를 조인해서 가져온다. 따라서 저런 함수들을 작성할 필요조차 없었다!
단방향 관계라면 조인해서 필요한 데이터를 가져오는 함수(쿼리)를 작성해야하지만 현재 코드는 모두 양뱡향 관계로 설정되었기 때문에 대부분의 조인은 JPA가 알아서 처리해준다.
PostService.java
return postRepository.findAll(pageable).map(PostResponse::from);
PostResponse.java
public record PostResponse(
Long postId,
String title,
String content,
String username,
List<String> hashtags,
LocalDateTime lastModifiedAt
) {
public static PostResponse of(Long postId, String title, String content, String username, List<String> hashtags, LocalDateTime lastModifiedAt) {
return new PostResponse(postId, title, content, username, hashtags, lastModifiedAt);
}
public static PostResponse from(Post entity) {
List<String> hashtags = entity.getPostHashtags().stream()
.map(PostHashtag::getHashtag)
.map(Hashtag::getHashtagName)
.toList();
return PostResponse.of(
entity.getId(),
entity.getTitle(),
entity.getContent(),
entity.getUserAccount().getUserId(),
hashtags,
entity.getModifiedAt()
);
}
}
따라서 PostService의 코드가 수행될 때 map(PostResponse::from) 부분에서 JPA는 Post와 연결된 Posthashtag, Hashtag와의 조인을 수행해 필요한 정보들를 가져온다.
Hibernate:
select
p1_0.post_id,
p1_0.id,
h1_0.id,
h1_0.created_at,
h1_0.created_by,
h1_0.hashtag_name,
h1_0.modified_at,
h1_0.modified_by
from
post_hashtag p1_0
left join
hashtag h1_0
on h1_0.id=p1_0.hashtag_id
where
p1_0.post_id in(?,?)
해당 메서드가 호출되었을 때의 쿼리문이다. JPA에서 적절하게 조인을 수행하는 쿼리문을 실행하는 것을 볼 수 있다.