[삽질 피하기] 객체지향 쿼리 (Native Query, JPQL)

2021. 4. 21. 17:27삽질 피하기

1. 객체지향 쿼리

JPA는 복잡한 검색 조건을 사용해서 엔티티 객체를 조회할 수 있는 다양한 쿼리 기술을 지원한다.

JPQL (Java Persistence Query Language)  
Criteria Query JPQL을 편하게 작성하도록 도와주는 API, 빌더 클래스 모음
Native SQL JPA에서 JPQL 대신 직접 SQL을 사용할 수 있다.
QueryDLS JPA가 공식 지원하는 기능은 아니지만 Criteria 처럼 JPQL을 편하게 작성하도록 도와주는 빌더 클래스, 비표준 오픈소스 프레임워크이다.
JDBC 직접 사용, MyBatis 같은 SQL 매퍼 프레임워크 필요하다면 JDBC를 직접 사용할 수 있다.

 

 

 

2. JPQL

  • 지루하게 반복되는 CRUD 문제를 세련된 방법으로 해결
  • 개발자는 인터페이스만 작성한다
  • @Query 어노테이션을 이용하여 JPQL을 직접 정의할 수 있다.

 

※ JPA는 카멜케이스에 대해 '_' 처리되며 자동으로 매핑이 된다.


[참고] 삽질 피하기 - @Query, @Modifying, @Transactional 어노테이션 사용법

 

 

 

 

3. Native Query

Native Query의 경우 자동으로 매핑이 되지 않는다. 따라서 개별적으로 코드를 작성해주거나 JPA를 지원하는 ResultSet Mapper인 QLRM으로 매핑을 해주어야 한다. (또는 Entity에 @SqlResultSetMapping()를 설정해주어 해결 가능)

implementation group: 'ch.simas.qlrm', name: 'qlrm', version: '1.7.1'
...

import lombok.RequiredArgsConstructor;
import org.qlrm.mapper.JpaResultMapper;
import org.springframework.stereotype.Repository;

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

@RequiredArgsConstructor
@Repository
public class BoardTypeCustomRepository {

    private final EntityManager entityManager;

    public List<BoardTypeCount> getBoardTypeCount() {

        String sql = " " +
                "SELECT bt.id, bt.board_name, bt.reg_date, bt.using_yn," +
                "(SELECT COUNT(*) FROM board b WHERE b.board_type_id = bt.id) as board_count " +
                "FROM board_type bt ";

        // 직접 매핑할 경우
//        List<BoardTypeCount> boardTypeCountList = entityManager.createNativeQuery(sql).getResultList();
//        List<Object[]> resultList = entityManager.createNativeQuery(sql).getResultList();
//        return resultList.stream().map(e -> new BoardTypeCount(e)).collect(Collectors.toList());

        // QLRM 방법
        Query nativeQuery = entityManager.createNativeQuery(sql);
        JpaResultMapper jpaResultMapper = new JpaResultMapper();

        return jpaResultMapper.list(nativeQuery, BoardTypeCount.class);
    }

}
...

import lombok.AllArgsConstructor;
import lombok.Builder;
import lombok.Data;
import lombok.NoArgsConstructor;

import java.math.BigInteger;
import java.sql.Timestamp;
import java.time.LocalDateTime;

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

    private Long id;
    private String boardName;
    private LocalDateTime regDate;
    private boolean usingYn;

    private Long boardCount;

    public BoardTypeCount(Object[] arrObj) {
        this.id = ((BigInteger)arrObj[0]).longValue();
        this.boardName = ((String)arrObj[1]);
        this.regDate = ((Timestamp)arrObj[2]).toLocalDateTime();
        this.usingYn = ((Boolean)arrObj[3]);
        this.boardCount = ((BigInteger)arrObj[4]).longValue();
    }

    public BoardTypeCount(BigInteger id, String boardName, Timestamp regDate, Boolean usingYn, BigInteger boardCount) {
        this.id = id.longValue();
        this.boardName = boardName;
        this.regDate = regDate.toLocalDateTime();
        this.boardCount = boardCount.longValue();
    }
}

[참고] https://mvnrepository.com/artifact/ch.simas.qlrm/qlrm

 

728x90