개발 환경
- Build : Gradle
- SpringBoot : 2.7.5
- Java : 11
- OS : Mac
요구사항
특정 GalleryId를 가진 작품(Artwork)List를 생성시간 기준 내림차순으로 응답하는 로직
즉, FindAll + 특정 FK(GalleryId)를 가진 Artwork만 조회하는 기능 + 정렬 필요
조건
Gallery : Artwork = 1:N 매핑
// Auditable에는 생성시간과 수정시간이 들어있음.
// Artwork Entity
@Entity
public class Artwork extends Auditable {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private Long artworkId;
...
@ManyToOne(fetch = FetchType.LAZY)
@JoinColumn(name = "GALLERY_ID")
private Gallery gallery;
}
// Gallery Entity
@Entity
public class Gallery extends Auditable {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private Long galleryId;
...
@OneToMany(mappedBy = "gallery")
private List<Artwork> artworkList = new ArrayList<>();
}
구현
기능을 구현하기 전 바로 생각나는 방법은 2가지가 떠올랐다.
첫 번째 방법
갤러리 객체를 불러와 갤러리에 있는 Artwork리스트를 조회한 다음 정렬하는 방법
하지만 이렇게 구현하게 되면이 도메인 별로 분리가 정확하게 되지 않기 때문에 좋지 않은 방법이었다.
두 번째 방법
쿼리메서드를 사용하여 ArtworkRepository에서 Artwork 내부에 있는 FK(gallery_id)를 이용하여 조회 및 정렬하는 방법이다.
방법 1. JPA 쿼리 메서드로 참조 객체 안에 있는 필드 사용하기
현재 Artwork 안에 있는 필드는 DB처럼 galleryId가 아닌 Gallery 필드가 존재한다.
따라서 galleryId를 이용해 조회하려면 Gallery.galleryId와 같이 조회를 해야 하는데 도저히 방법이 떠오르지 않았다.
JPQL을 사용하기에는 성능상도 그렇고 직접 쿼리를 명시해야 한다는 단점으로 인해 왠만하면 쿼리메서드를 사용하라는 글들이 보였고,
할 수 없이 계속 구글링을 하던 중에 결국 방법을 찾아냈다..
일단 결론부터 말하면 다음과 같다.
리턴타입 + 주제 + [참조객체]_[필드명]
# 조회 쿼리 메서드로 예시
리턴타입 findBy참조객체_필드명(필드타입 변수명);
여기서 첫 글자들은 대문자로 시작(JPA의 작성 규칙)해야 한다.
내가 구현해야 할 기능은 FK(galleryId)를 이용해 조회하는 기능으로, Gallery(참조객체) 안에 있는 galleryId(필드)를 사용해야 한다.
적용하게 된다면 다음과 같다.
List<Artwork> findAllByGallery_GalleryId(long galleryId);
이렇게 작성하면 Artwork 전체를 조회하는데 Artwork 안에 있는 gallery 안에 있는 galleryId를 이용해 조회하게 된다.
위에서 사용한 _가 Java에서의 .의 기능을 하고 있다고 생각하면 될 듯 하다.
마지막으로 정렬 기능을 넣기 위해 매개변수로 Sort를 받게 처리하였다.
// ArtworkRepository
List<Artwork> findAllByGallery_GalleryId(Long galleryId, Sort sort);
// ArtworkService
List<Artwork> artworkList = artworkRepository.findAllByGallery_GalleryId(galleryId,
Sort.by(desc("createdAt")));
테스트
테스트코드를 올릴까 하다가 코드보다는 포스트맨 결과가 더 보기 쉬울 것 같아 포스트맨 진행 결과를 남기려고 한다.
테스트를 진행하기 위해 애플리케이션이 실행 되기 전 다음과 같은 쿼리문을 실행한다.(sample data)
INSERT INTO ARTWORK (title, content, image_path, created_at, last_modified_at ,gallery_id, member_id) values
('갤러리1-작품1', '다들 화이팅입니다!', '/1.jpg', '2022-11-16T23:41:57.764644', '2022-11-16T23:41:57.764644', 1, 2),
('갤러리1-작품2', '다들 화이팅입니다!', '/2.jpg', '2022-11-16T23:42:57.764644', '2022-11-16T23:42:57.764644', 1, 6),
('갤러리1-작품3', '다들 화이팅입니다!', '/3.jpg', '2022-11-16T23:43:57.764644', '2022-11-16T23:43:57.764644', 1, 7),
('갤러리1-작품4', '다들 화이팅입니다!', '/4.jpg', '2022-11-16T23:44:57.764644', '2022-11-16T23:44:57.764644', 1, 8),
('갤러리2-작품1', '다들 화이팅입니다!', '/4.jpg', '2022-11-16T23:45:57.764644', '2022-11-16T23:45:57.764644', 2, 8),
('갤러리2-작품2', '다들 화이팅입니다!', '/4.jpg', '2022-11-16T23:46:57.764644', '2022-11-16T23:46:57.764644', 2, 8);
만약 테스트가 잘 진행되었다면, galleryId 별로 조회할 수 있을 듯 하다.
포스트맨 - galleryId 1을 가진 작품 조회 요청 결과
포스트맨 - galleryId 2을 가진 작품 조회 요청 결과
생성일자로 내림차순하여 정상적으로 데이터를 조회하는 것을 확인할 수 있다!
Reference
How to use Spring Data JPA Repository to query from 2 tables?
I have 2 tables say Student and Teacher and say Student has a Many-To-One relationship to Teacher and say, teacherId serves as the foreign key. How can I use spring data JPA repo methods, in a way -
stackoverflow.com
'SpringBoot' 카테고리의 다른 글
[SpringBoot] AWS S3 파일(이미지) 업로드 및 삭제하기 구현 (0) | 2022.11.28 |
---|---|
[SpringBoot] MockMvc - multipart() POST외 다른 HTTPMethod 사용하기 (0) | 2022.11.26 |
[TroubleShooting] SpringBoot Controller Test - MockMvc 302 Found, 403 Forbidden (0) | 2022.11.24 |
[Trouble Shooting] MaxUploadSizeExceededException (0) | 2022.11.03 |
[에러해결] HttpMediaTypeNotAcceptableException: Could not find acceptable representation (0) | 2022.09.04 |