본문 바로가기
개발/스프링부트

[Spring Data Jpa] Native query DTO Projection

by hamcheeseburger 2021. 7. 25.

1. Interface dto로 Projection

- DTO

public interface InterfaceDTO {
	// 규칙에 맞게 메소드 정의 (필드처럼 사용 가능)
	int getTableId();
	String getName();
	String getBrand();
}

- JPA Repository (Pageable이 필요하다는 가정)

Pageable로 페이징 가능,

Pageable에 정의된 Sort방식 적용 가능!!

 

(1) Page 객체로 받을 때 : countQuery 속성 꼭 필요!!

interface dto가 가지고 있는 필드 명에 맞게 alias를 정의하면 자동으로 매칭됨

@Query(value= "SELECT tn.id as tableId, tn.name as name, tn.brand as brand "
	+ "FROM TableName tn WHERE tn.name = :keyword"
	countQuery= "select count(*) "
			+ "FROM TableName tn WHERE tn.name=:keyword",
	nativeQuery=true)
Page<InterfaceDTO> searchKeyword(@Param("keyword") String keyword, Pageable pageable);

 

(2) List 객체로 받을 때 : countQuery 속성 생략 가능

@Query(value= "SELECT tn.id as tableId, tn.name as name, tn.brand as brand "
	+ "FROM TableName tn WHERE tn.name = :keyword"
	nativeQuery=true)
List<InterfaceDTO> searchKeyword(@Param("keyword") String keyword, Pageable pageable);

 

2. Class DTO로 Projection (NamedNativeQuery 필요)

별로 추천하는 방식은 아님. 차라리 query dsl을 사용하는게 코드 가독성이나 유지보수에 용이함.

- DTO

projection 할 필드에 대한 생성자 반드시 필요!

public class ClassDTO {
	private int tableId;
    private String name;
    private String brand;
    
    public ClassDTO() {
    	super();
    }
    
    // projection 할 필드에 대한 생성자 반드시 필요!
    public ClassDTO(int tableId, String name, String brand) {
    	super();
        this.tableId = tableId;
        this.name = name;
    	this.brand = brand;
    }
    
    // getter, setter 생략
}

- Entity

entity 객체에 NamedNativeQuery, SqlResultSetMapping 정의

@Entity
@Table(name="TableName")
@NamedNativeQuery(
	    name = "searchWithNamedQuery",
	    query = "SELECT tn.table_id as tableId, tn.name as name, tn.brand as brand "
	    		"FROM TableName tn",
	    resultSetMapping = "tableclassdto"
	)

@SqlResultSetMapping(
	    name = "tableclassdto",
	    classes = @ConstructorResult(
	        targetClass = ClassDTO.class,
	        columns = { // 생성자 파라미터 순서에 유의
	            @ColumnResult(name = "tableId", type = Integer.class),
	            @ColumnResult(name = "name", type = String.class),
	            @ColumnResult(name = "brand", type = String.class),
	        }
	    )
	)
public class TableName {
	// 이하 생략

}

- JPA Repository (Pageable이 필요하다는 가정)

Pageable로 페이징 가능,

Pageable에 정의된 Sort방식 적용 불가능 (order by 사용해야 함)

 

(1) Page 객체로 받을 때 : NamedNativeQuery에 countQuery 속성 꼭 필요!!

@Query(name="searchWithNamedQuery", nativeQuery = true)
Page<ClassDTO> searchWithNamedQuery(@Param("keyword") String keyword, Pageable pageable);

(2) List 객체로 받을 때 : NamedNativeQuery에 countQuery 속성 생략 가능

@Query(name="searchWithNamedQuery", nativeQuery = true)
List<ClassDTO> searchWithNamedQuery(@Param("keyword") String keyword, Pageable pageable);

 

** 참고

class DTO projection에서 jpa repository를 interface DTO projection 방식대로 사용한다면 convert exception이 발생한다.

NamedNativeQuery를 사용해야만 class DTO로 projection이 가능하다.

이전 댓글