HIRO Tracks

山根正大です。ソフトウェアエンジニアが日々学んだ知識を発信します。

【Querydsl】必要なカラムだけDTOにマッピングする(Projections.constructor)

これは何?

queryDSLで「SELECT * FROM...」するのではなく、必要なカラムだけ取得する方法をお伝えします。

クエリチューニングの一環としてでSELECTする対象を絞り込む時(Key LookUpを減らして実行計画改善する時とか)に便利なTipになってます!

解決したい課題

  • queryDSLで必要なカラムだけ取得したい
  • その際、@Entityクラスではなく、自分で作ったDTO的なクラスに結果をマッピングしたい

そもそもqueryDSLとは

JPA+HibernateでSQLを実装する際、型安全な実装を可能にしてくれるライブラリ。

Querydsl - Unified Queries for Java

結論:Projections.constructorを使う

Projectiosns.constructorというメソッドによって、DTOに結果をマッピングします。

TABLE

↓このbookテーブルに対して、release_date以外のデータを取ってくることを想定します。

CREATE TABLE book (
  id VARCHAR(255) PRIMARY KEY,
  title VARCHAR(255) NOT NULL,
  author VARCHAR(255) NOT NULL,
  release_date DATETIME NOT NULL //この行は今回取得したくない!!!
);

TABLEクラス

import java.time.LocalDateTime
import javax.persistence.Entity
import javax.persistence.Id
import javax.persistence.JoinColumn
import javax.persistence.OneToMany
import javax.persistence.Table

@Entity
@Table(name = "book")
class BookEntity(
    @Id
    var id: String? = null,
    val title: String? = null,
    val author: String? = null,
    val releaseDate: LocalDateTime? = null,
)

DTOクラス

class BookDto(
    val id: String,
    val title: String,
    val author: String,
)

クエリメソッド

select句の中にProjections.constructorメソッドを入れて、DTOにマッピングします。

import com.querydsl.core.types.Projections
import com.querydsl.jpa.impl.JPAQueryFactory
import com.sample.infra.jpa.entity.QBookEntity //自動生成されるQEntity
import com.sample.usecase.query.BookDto

val queryFactory: JPAQueryFactory  = JPAQueryFactory(entityManager); //entityManagerはjavax.persistence.EntityManager
val book = QBookEntity.bookEntity //自動生成されるQEntity

val result = queryFactory.select(
    Projections.constructor(
        BookDto::class.java,
        book.id,
        book.author,
        book.title,
    )
).from(book).where(book.id.eq(id)).fetchOne()

公式ドキュメントも参考にしてみてください!

javadoc.io

サンプル実装

github.com

より上級編記事も書いてます!

hiro-tracks.net