본문 바로가기
Spring/JPA + Security

[Spring Data JPA] 구독하기 구현하기 -4 구독리스트 구현, JPQL 사용한 Native Query

by pyogowoon 2023. 1. 11.

 

 

 ★ 우선 들어가기전에 그동안 사용해왔던 방법인 네이티브 쿼리 방식은 이번에 사용되지않는다.

 

그러한 이유는

우리가 새로 짠 스칼라쿼리에서 동일 유저인지 판단 쿼리에서 select ~ if ~ if 문의 리턴값은

Repository가 받아들이는 리턴값인 JparRepository<Subscribe, Integer> 의 subscribe인데 쿼리의 리턴값은 subscribe가 아니여서 네이티브 쿼리를 사용할 수 없다.

 

 

그렇기 떄문에 이번에는 service 에서 직접 네이티브쿼리를 짤것이다.

JPQL(Java Persistence Query Language) 사용

 

- 테이블이 아닌 엔티티 객체를 대상으로 검색하는 객체지향 쿼리

- SQL을 추상화해서 특정 데이터베이스 SQL에 의존하지 않음

- JPA는 JPQL을 분석한 후 적절한 SQL을 만들어 데이터베이스를 조회

- 방언(Dialect)만 변경하면 JPQL을 수정하지 않고 자연스럽게 DB 변경 가능

 

SubscribeService

import lombok.RequiredArgsConstructor;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import javax.persistence.EntityManager;
import javax.persistence.Query;
import java.util.List;
import java.util.stream.Collectors;


@RequiredArgsConstructor
@Service
public class SubscribeService {

    private final SubscribeRepository subscribeRepository;
    private final EntityManager em;
    
    									.
                                        .
                                        .
                                        .
                                        .
                                        
    
    
    
    
@Transactional(readOnly = true)
    public List<SubscribeDto> 구독리스트(int principalId, int pageUserId){

        //쿼리 준비
        StringBuffer sb = new StringBuffer();
        sb.append("SELECT u.id, u.username, u.profileImageUrl, "); //맨 끝에 꼭 한칸띄워야함
        sb.append("if ((SELECT 1 FROM subscribe WHERE fromUserId = ? AND toUserId = u.id), 1,0) subscribeState, ");
        sb.append("if ((?=u.id), 1, 0) equalUserState ");
        sb.append("FROM user u INNER JOIN subscribe s ");
        sb.append("ON u.id = s.toUserId ");
        sb.append("WHERE s.fromUserId = ?");

        //1. principalId
        //2.맨 끝 두번째 물음표 principalId
        //3.마지막 물음표 pageUserId ,

        //쿼리 완성
        Query query = em.createNativeQuery(sb.toString())
                .setParameter(1, principalId)
                .setParameter(2, principalId)
                .setParameter(3, pageUserId);

        //쿼리 실행 (qlrm 라이브러리 필요 DTO에 DB결과를 매핑하기 위해서)
//        JpaResultMapper result = new JpaResultMapper();
//        List<SubscribeDto> results = result.list(query, SusbcribeDto.class)
        

        //쿼리 실행 (qlrm 라이브러리 없어서 이렇게 받음)
        List<Object[]> results = query.getResultList();
        List<SubscribeDto> subscribeDtos = results.stream()
                .map(o -> new SubscribeDto(o))
                .collect(Collectors.toList());

        return subscribeDtos;
    }

 qlrm 라이브러리가 없기 때문에  아래의 방법을 채택했다.

 

@Builder
@NoArgsConstructor
@AllArgsConstructor
@Data
public class SubscribeDto {

    private int id;
    private String username;
    private String profileImageUrl;
    private Integer subscribeState;
    private Integer equalUserState;


    public SubscribeDto(Object[] object) {
        this.id = (int) object[0];
        this.username = (String) object[1];
        this.profileImageUrl = (String) object[2];
        this.subscribeState = Integer.parseInt(String.valueOf(object[3]));
        this.equalUserState = Integer.parseInt(String.valueOf(object[4]));

    }
}

 

 

 

 

query.getResultList(); == SELECT 쿼리를 실행하고 쿼리 결과를 컬렉션으로 반환한다.

결과가 없다면 빈 컬렉션이 반환된다.

stream().map() === 람다식을 사용하기 위해 stream 을 사용했고 map은 요소들을 특정 조건에 해당하는 값으로 변환해준다.

여기에선 모든 타입을 SusbcribeDto에 있는 object 생성자를 만들어서 거기에 넣었고 .collect(collectors.toList() 인자에 전달해서 List 객체로 리턴

 

Collectors를 이용하여 스트림의 요소들을 List 객체로 변환할 수 있다.

아래와 같이 Collectors.toList()를 인자에 전달하면 List 객체로 리턴된다.

 

포스트맨으로 테스트를 해보면

 

 

1번 유저로 로그인 하고

 2번유저를 확인해보면 

 

 

우리가 원하는데로

 아이디, 유저네임 , url (현재 구현하지않았기떄문에 null) 이 나오고

1번유저가 2번유저를 본 상황이고 2번유저를 구독한 유저가 1번,3번이므로 잘 나왔고

id = 1인 user의 equalUserState가 1 즉 같은사람 이라는걸 알려준다.

 

구독 리스트가 정상적으로 가져와진다.

댓글