web 개발/DB

<JPA>jpa 내에서 동적 sql 처리

잼추 2024. 5. 28. 03:38
  • 동적 쿼리
    • 상황에 따라 내용이 바뀌는 쿼리

 

  • JPA Specification
    • 외부 라이브러리를 사용하지 않는 방식
    • 기존의 repository 인터페이스에 JpaSpecificationExcutor 상속, 동적쿼리 사용을 위한 클래스 생성
      • 사용 1: title에 search contents를 포함하는 값을 모두 들고오기
        public static Specification<Post> titleContains(String searchContent) {
            return (root, query, criteriaBuilder) -> {
                return criteriaBuilder.like(root.get("title"), "%" + searchContent + "%");
            };
        }
      • 사용 2: subquery 생성하여 join 하여 검색 후 들고오기 
      • public static Specification<Post> tagNameContains(String searchTag) { return (root, query, criteriaBuilder) -> { // 서브쿼리를 생성합니다. Subquery<Long> postTagsSubquery = query.subquery(Long.class); Root<PostTags> postTagsRoot = postTagsSubquery.from(PostTags.class); Join<PostTags, Tag> tagJoin = postTagsRoot.join("tag"); // 태그 이름으로 필터링 조건을 생성합니다. Predicate tagNamePredicate = criteriaBuilder.equal(tagJoin.get("tagName"), searchTag); // 서브쿼리의 select 절을 설정합니다. PostTags에서 Post의 ID를 선택합니다. postTagsSubquery.select(postTagsRoot.get("post").get("id")) .where(tagNamePredicate); // 메인 쿼리에서 Post의 ID가 서브쿼리의 결과에 포함되는 조건을 설정합니다. return criteriaBuilder.in(root.get("id")).value(postTagsSubquery); }; }
    • 각 메소드를 따로 작성후 service에 이식 해주었다. 동적쿼리 작성 완료!!
      public Page<PostResponseForSearchDto> getPostBySearch(PostRequestDtoForSearch requestDto, Pageable pageable) {
          Specification<Post> spec = Specification.where(PostSpecifications.distinct());
      
          if (requestDto.getSearchContent() != null && !requestDto.getSearchContent().isEmpty()) {
              spec = spec.and(PostSpecifications.titleContains(requestDto.getSearchContent()));
          }
          if (requestDto.getSearchTags() != null && !requestDto.getSearchTags().isEmpty()) {
              spec = spec.and(PostSpecifications.tagNameContains(requestDto.getSearchTags()));
          }
      
          Page<Post> postPage = postRepository.findAll(spec, pageable);
          return postPage.map(this::convertToDto);
      }
    • builder 패턴을 이용한 responseDto 내용 작성
      private PostResponseForSearchDto convertToDto(Post post) {
          MemberProfile memberProfile = memberProfileRepository.findByMemberId(post.getMember().getId(), post.getMember().isDeletedYn()).orElseThrow();
          PostDetail postDetail = postDetailRepository.findByPostId(post.getId()).orElseThrow();
          PostResponseForSearchDto response =  PostResponseForSearchDto.builder()
                  .postId(post.getId())
                  .title(post.getTitle())
                  .memberProfileId(memberProfile.getId())
                  .memberNickname(memberProfile.getNickName())
                  .memberProfileImage(memberProfile.getProfileImage())
                  .view(post.getView())
                  .likeCount(post.getLikeCount())
                  .createdAt(post.getCreatedAt())
                  .updatedAt(post.getUpdatedAt())
                  .content(postDetail.getContent())
                  .build();
          return response;
      }
      


이미 작성 되어있는 entity는 손을 대지 못하고 특정 entity는 이미 join 되어있는 상태에서 사용하려고 했다.
하지만 post id와 tag id 로 join 되어있는 주체가 post tag였는데

이미 다른 메소드들이 post 로 작성 되어있는 상황이었다.

해당 메소드의 주체를 post로 시작하여 return 값도 post가 되어야 했기에 메소드 설계 자체가 까다로웠다.

 

 
 

 

 

 

 

'web 개발 > DB' 카테고리의 다른 글

프로젝트 ERD  (0) 2024.06.21