일 | 월 | 화 | 수 | 목 | 금 | 토 |
---|---|---|---|---|---|---|
1 | 2 | 3 | 4 | 5 | 6 | 7 |
8 | 9 | 10 | 11 | 12 | 13 | 14 |
15 | 16 | 17 | 18 | 19 | 20 | 21 |
22 | 23 | 24 | 25 | 26 | 27 | 28 |
29 | 30 |
- 중복컬럼dto매핑
- ls -lgaf
- 쿼리실행순서
- 컬럼명중복
- Flush
- Oracle
- 로컬에서 플러그인 추가
- port&adapter architecture
- 플러그인 로컬 테스트
- 포트앤어댑터 아키텍처
- 쓰기지연저장소
- hibernate 쿼리실행 순서
- dto매핑우선순위
- sql 테스트 사이트
- group by group by rollup 차이
- 스트림
- 쓰기지연sql저장소 쿼리실행순서
- intellij 플러그인 개발
- 쿼리테스트사이트
- Java
- 오라클쿼리테스트사이트
- JPA
- Kafka
- 자바
- Stream
- java 로 intellij 플러그인
- intellij 플러그인 만들기
- IntelliJ
- plugin local
- error 2002 (hy000): can't connect to local mysql server through socket '/tmp/mysql.sock' (2)
- Today
- Total
개린이 탈출기
[QueryDsl] DTO로 결과 반환하기 (Projections) 본문
QueryDsl을 활용하여 데이터를 조회할 때, @Entity로 매핑된 클래스와 다른 형태로 데이터를 조회해야 할 때가 종종 발생한다.
이때 활용하기 좋은 방법 몇가지를 소개하려고 한다.
기본 TUPLE 활용
우선 말해두고 싶은 점은 이 방식은 QueryDsl을 사용하는 레이어 외의 다른 영역에서도 사용할 예정이라면 의존성 관리 측면에서 추천하지 않는 방식이다.
Tuple이라는 클래스는 QueryDsl 이 제공하는 클래스이기 때문에 외부에서 사용하는 경우, 의존성에 영향을 미치게 되므로 내부에서 사용하는 경우에 활용하는 것이 좋아 보인다.
List<Tuple> categoryTupleList = jpaQueryFactory
.select(
qCategoriesJpo.categoryname,
qCategoriesJpo.description
)
.from(qCategoriesJpo)
.fetch();
for (Tuple row : categoryTupleList) {
// tuple 의 get 메서드를 활용하여 컬럼 값 추출
String categoryname = row.get(qCategoriesJpo.categoryname);
String description = row.get(qCategoriesJpo.description);
System.out.println("카테고리 : " + categoryname);
System.out.println("설명 : " + description);
}
아래의 세가지 방법은 QueryDsl에서 제공하는 Projections 클래스를 활용하는 방식이다.
이 방식들을 사용하면 쿼리 결과를 DTO 클래스 등에 바로 입력하여 사용할 수 있다.
프로퍼티 접근법
Projections 의 beans 메서드를 활용하는 방법으로, 지정한 클래스의 setter를 통해 컬럼 값을 넣는 방식이다.
기본생성자를 이용하여 클래스를 생성하고 setter를 통해 값을 넣는 것이 특징이다.
setter 를 활용하기 때문에 불변 객체엔 값을 제대로 할당할 수 없다.
List<SampleDto> categories2 = jpaQueryFactory
.select(Projections.bean(SampleDto.class,
qCategories.categoryname,
qCategories.description)
).from(qCategories)
.fetch();
필드 직접 접근법
Projections 의 fields 메서드를 활용하는 방법으로, 지정한 클래스의 필드에 값을 직접 주입하는 방식이다.
@Autowired 처럼 동작하기 때문에 컬럼명과 필드명을 올바르게 일치시켜야 값이 제대로 주입된다.
마찬가지로 불변 객체엔 값을 제대로 주입할 수 없다.
List<SampleDto> categories3 = jpaQueryFactory
.select(Projections.fields(SampleDto.class,
qCategories.categoryname,
qCategories.description)
).from(qCategories)
.fetch();
생성자 접근법
Projections 의 consturctor 메서드를 활용하는 방법으로, 지정한 클래스의 적절한 생성자를 찾아 값을 넣는 방식이다.
참고로 constructor 메서드의 내부를 살펴보면 전달받은 파라미터를 각각 클래스타입 배열과 값 리스트로 나누어 활용한다.
파라미터의 순서가 정확하지 않는 경우, 의도와 다르게 값이 들어갈 수도 있고, 오류 발생 시 런타임 오류가 발생한다.
따라서 생성자에 명시한 파라미터의 순서를 정확히 맞춰 값을 넘겨주어야 한다.
List<SampleDto> categories4 = jpaQueryFactory
.select(Projections.constructor(SampleDto.class, qCategories.categoryname, qCategories.description)
).from(qCategories)
.fetch();
@QueryProjection
컴파일 시점에 Q클래스를 만들어 활용하는 방식이다.
이 방식 또한 생성자를 활용하는데, 차이점은 본 클래스의 생성자가 아닌 Q클래스의 생성자를 활용한다는 점이다.
따라서 기존 생성자 방식에서 잡지 못했던 오류를 컴파일 과정에서 발견할 수 있으므로 생성자 접근법과 비교했을 때 더 안정적이라고 볼 수 있다.
그러나 QueyDsl이 제공하는 아노테이션인 만큼 의존성 관리에 주의가 필요하다.
@Getter
@Setter
@NoArgsConstructor
@AllArgsConstructor
public class SampleDto {
private Long categoryid;
private String categoryname;
private String description;
@QueryProjection
public SampleDto(String categoryname, String description) {
this.categoryname = categoryname;
this.description = description;
}
}
List<SampleDto> categories5 = jpaQueryFactory
.select(new QSampleDto(qCategories.categoryname, qCategories.description))
.from(qCategories)
.fetch();
참고로 DTO로 조회한 것들은 영속성 관리 대상이 아니다.
참고
http://querydsl.com/static/querydsl/4.0.1/reference/ko-KR/html_single/#d0e2002
https://pyoungt.tistory.com/215
https://velog.io/@bagt/QueryDsl-DTO-Projection
'Database ~ SQL' 카테고리의 다른 글
[ORACLE] GROUP BY 와 ROLLUP 이 헷갈릴 때 (0) | 2025.04.02 |
---|---|
[MyBatis] 조회 시, 컬럼 명이 중복되도록 조회하는 경우 (alias 사용) (0) | 2025.03.27 |
[SQL] 여러 개의 행을 하나의 데이터로 합치고 싶다면 LISTAGG/GROUP_CONCAT (0) | 2025.03.14 |
쿼리 실행해볼 수 있는 쿼리 SQL 사이트 추천 (0) | 2025.03.14 |
[ORACLE] 접속한 유저와 이름이 다른 스키마로 연결하는 방법 (0) | 2025.01.06 |