반응형

우리가 뽑아야 할 정보는 
1. 유저정보
2. 구독했는지 여부
3. 동일인인지 여부 - test1으로 로그인했는데 팔로우 정보에 test1이 있을때 팔로우 버튼이 안보이게 해야 하므로

시나리오
test1으로 로그인 했고 test2의 팔로우 정보를 보려한다. 
그럴때 아래와 같이 1) test2가 본인(test1)을 팔로 했을때는 팔로우관련 버튼이 안보이게 하고
2) test1의 팔로우 상황에 따라 다른 유저 팔로우 버튼을 달리 보이게 해야한다. 

 


현재 2번 페이지의 주인(fromUserId) 는 1번과 3번을 팔로우 하고 있기 때문에
팔로우 모달에서는 1번 유저와, 3번 유저의 정보가 나와야한다. 

그러기 위해선 user 테이블과 follow테이블이 조인해야한다. 
(user.id = follow.toUserId)

 

조인쿼리-
-> 이렇게 하면 모든 정보가 가져와지기 때문에

유저아이디, 유제이름, 유저의 프로플 사진 경로 정보만 가져온다.

 

 1. followState 컬럼 관련 쿼리작성 - 팔로우 여부 확인

그 다음에는 로그인한 유저(1번)이 3번을 팔로우 했는지 여부를 확인해야한다. (1번은 자기 자신이기 때문에 확인할 필요 X)
-> 팔로우 한다면 1번 컬럼에 1이 나온다.



그래서 이 결과를 아까의 조인 컬럼 옆에다 붙여야한다. 
id 1 열은 자기 자신이니까 아무 정보가 없어야하고 id 3열에는 팔로우 하고 있으니까 숫자 1이 있어야 하겠다. 

 

그러기 위해서는 스칼라 서브쿼리가 필요하다. 
스칼라 서브쿼리: select 절 안에 select문 있는것!
스칼라 서브쿼리는 단일행을 리턴해야 한다. 예컨대 아래와 같은 스칼라쿼리는 단일이 아닌 여러 행를 반환하므로 오류가 발생한다. 


followState 컬럼에는 로그인한 유저(여기선 1번)이 1번 유저를 팔로우 하는지, 또 3번 유저를 팔로우 하는지
에 관한 정보를 표기해야한다. 
따라서 스칼라서브쿼리에서  아래의 SELECT문(1번 유저가 특정 유저를 팔로하는지 확인하는 쿼리)을 복붙해서 
넣어주고 toUserId에 변수로 u.id를 넣어주면 된다.

결과

 

 2. 관련 쿼리작성 - 동일 유저 확인

다음으로 조회된 유저들이  로그인 유저(fromUserId)와  같은지를 판단하는 쿼리 및 컬럼을 만들어야한다. 
첫째열은 동일 유저니까 1이 나오는게 맞지만 둘째열은 아니니까 0으로 나와야한다. 

(1 = u.id) : 만약 로그인한 아이디(1)과 조회된 id가 같으면 1, 다르면 0을 표기한다.
*마리아db에서는 '==' 을 '=' 으로 쓴다. 

followState컬럼과 equalUserState컬럼의 값이 결과가 true면 1,아니면 0만 나오도록 if 문으로 감싼다. 
->최종 완료

===============================================

이렇게 만들어진 쿼리는 
FollowRepositoy 에 작성이 안된다. 왜냐하면 FollowRepositoy 의 반환타입은 Follow 모델인데 결과같은 Follow모델이 아니기 때문이다.
(public interface FollowRepositoy extends JpaRepository<Follow,Integer>{})

따라서 
FollowService에서 직접 네이티브 쿼리로 짜줘야한다. 

FollowService

- EntityManager를 DI해야한다. 
  모든 Repository 는 EntityManager를 구현해서 만들어져 있는 구현체이기 때문에 

1) 쿼리준비단계
StringBuffer로 한 줄씩 쿼리를 append해준다. 
여기서 주의해야할 점은 마지막 한 칸은 꼭 비워줘야한다. 안 띄워주면 다음 줄의 쿼리가 바로 붙어버린다.
또한 마지막에 세미콜론은 첨부하면 안된다.

2) 쿼리 완성단계
 1.물음표: principalId
 2.물음표 : 로그인한 아이디, principalId
 3. 물음표 : 현재 페이지 주인 아이디, pageUserId

3) 쿼리 실행단계
result.list(query, FollowDto.class);
: 쿼리 결과가 1건이 아니므로 resut.list메소드를 사용해준다. (단건이라면 uniqueResult 사용)
  매개변수로는 쿼리와 반환받을 타입(dto)를 넣어준다. 

JpaResultMapper 는 qlrm 라이브러리로부터 import 받아온건데,
qlrm이란 db에서 result된 결과를 자바클래스(dto)에 매핑해주는 라이브러리
내가 리턴받을 결과가 모델이아닌, 새로운 조합의 데이터면, dto라면 네이티브쿼리를 써야한다. jpa 못쓴다.

@RequiredArgsConstructor
@Service
public class FollowService {

    private final FollowRepositoy followRepositoy;
    private final EntityManager em;

    @Transactional(readOnly = true)
    public List<FollowDto> followList(int principalId, int pageUserId){
        //쿼리 준비
        StringBuffer sb = new StringBuffer();
        sb.append("SELECT u.id, u.username, u.profileImageUrl, ");
        sb.append("if((SELECT 1 FROM follow WHERE fromUserId = ? AND toUserId = u.id), 1, 0) followState, ");
        sb.append("if((? = u.id), 1, 0)equalUserState ");
        sb.append("FROM user u INNER JOIN follow f ");
        sb.append("ON u.id = f.toUserId ");
        sb.append("WHERE f.fromUserId = ? "); //세미콜론 첨부하면 안됨

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

        //1.물음표: principalId
        //2.물음표  :principalId
        //3. 물음표 :pageUserId

        JpaResultMapper result = new JpaResultMapper();
        List<FollowDto> followDtos = result.list(query, FollowDto.class);//한건을 받을게 아니니까

        return  followDtos;

    }
...
}

+ Recent posts