Statements

JPQL은 select, update, delete statement를 지원합니다. Kotlin JDSL은 이 statement들을 만들 수 있는 DSL을 제공합니다.

Select statement

jpql()에서 select()를 호출하는 것으로 select statement를 만들 수 있습니다.

val query = jpql {
    select(
        path(Employee::employeeId),
    ).from(
        entity(Employee::class),
        join(Employee::departments),
    ).where(
        type(entity(Employee::class)).eq(FullTimeEmployee::class)
    ).groupBy(
        path(Employee::employeeId),
    ).having(
        count(Employee::employeeId).greaterThan(1L),
    ).orderBy(
        count(Employee::employeeId).desc(),
        path(Employee::employeeId).asc(),
    )
}

Select clause

select statement의 select clause를 만들기 위해, select()를 이용할 수 있습니다. select()Expression을 파라미터로 받아 프로젝션을 표현합니다. 만약 하나의 Expressionselect()에 넘어온다면 타입 추론으로 select statement의 타입을 결정하지만 하나 이상의 Expression이 넘어온다면 타입 명시가 필요합니다.

// It can infer the result type.
select(path(Author::authorId))

// It cannot infer the result type.
select(path(Author::authorId), path(Author::name))

// This allows it to know the result type.
select<CustomEntity>(path(Author::authorId), path(Author::name))

DTO projection

DTO 클래스와 클래스의 생성자를 selectNew()에 넘기는 것으로 DTO 프로젝션을 만들 수 있습니다.

data class Row(
    val departmentId: Long,
    val count: Long,
)

selectNew<Row>(
    path(EmployeeDepartment::departmentId),
    count(Employee::employeeId),
)

From clause

select statement의 from clause를 만들기 위해, from()을 이용할 수 있습니다. from()EntityJoin을 파라미터로 받아 어떤 entity를 통해 조회가 되는지 표현합니다.

from(
    entity(Author::class),
    join(BookAuthor::class).on(path(Author::authorId).equal(path(BookAuthor::authorId))),
)

Join

조회되는 entity를 조인하기 위해, join()fetchJoin()을 사용할 수 있습니다. Join에는 2종류가 있으며 일반 Join과 연관관계 Join이 있습니다. 두 Join은 연관관계가 있는 entity를 조인하는지 없는 entity를 조인하는지에 따라 구별됩니다.

@Entity
// ...
class Book(
    // ...

    @OneToMany(mappedBy = "book", cascade = [CascadeType.ALL], orphanRemoval = true)
    val authors: MutableSet<BookAuthor>,
)

@Entity
// ...
class BookAuthor(
    @Id
    @Column(name = "author_id")
    val authorId: Long,
) {
    @Id
    @ManyToOne
    @JoinColumn(name = "isbn")
    lateinit var book: Book
}

@Entity
// ...
class Author(
    @Id
    @Column(name = "author_id")
    val authorId: Long,

    // ...
)

from(
    entity(Book::class),
    join(Book::authors), // Association Join
    join(Author::class).on(path(BookAuthor::authorId).eq(path(Author::authorId))), // Join
)

join() 이후에 as()를 호출하는 것으로 조인될 entity에 alias를 부가할 수 있습니다. 만약 동일한 타입의 entity를 여러개 from clause에 포함시킬 때 이 기능을 이용할 수 있습니다.

from(
    entity(Book::class),
    join(Book::authors).`as`(entity(BookAuthor::class, "author")),
)

Where clause

select statement의 where clause를 만들기 위해, where()를 사용할 수 있습니다. where()Predicate를 파라미터로 받아 조회 데이터의 제약을 표현합니다. where()and()의 축약어로 whereAnd()를 사용할 수 있습니다. 마찬가지로 where()or()의 축약어로 whereOr()을 사용할 수 있습니다.

where(
    path(Book::publishDate).between(
        OffsetDateTime.parse("2023-01-01T00:00:00+09:00"),
        OffsetDateTime.parse("2023-06-30T23:59:59+09:00"),
    ),
)

Group by clause

select statement의 group by clause를 만들기 위해, groupBy()를 사용할 수 있습니다. `groupBy() 는 Expression을 파라미터로 받아 데이터의 그룹핑을 표현합니다.

groupBy(
    path(EmployeeDepartment::departmentId),
)

Having clause

select statement의 having clause를 만들기 위해, having()을 사용할 수 있습니다. having()Expression을 파라미터로 받아 추가적인 조회 데이터의 제약을 표현합니다. having()and()의 축약어로 havingAnd()를 사용할 수 있습니다. 마찬가지로 having()or()의 축약어로 havingOr()을 사용할 수 있습니다.

having(
    count(Employee::employeeId).greaterThan(1L),
)

Order by clause

select statment의 order by clause를 만들기 위해, orderBy()를 사용할 수 있습니다. orderBy()Sort를 파라미터로 받아 데이터의 정렬을 표현합니다.

orderBy(
    path(Book::isbn).asc(),
)

Update statement

jpql()에서 update()를 호출하는 것으로 update statement를 만들 수 있습니다.

val query = jpql {
    update(
        entity(Book::class)
    ).set(
        path(Book::price)(BookPrice::value),
        BigDecimal.valueOf(100)
    ).set(
        path(Book::salePrice)(BookPrice::value),
        BigDecimal.valueOf(80)
    ).where(
        path(Book::isbn).eq(Isbn("01"))
    )
}

Update clause

update statment의 update clause를 만들기 위해, update()를 사용할 수 있습니다. update()Entity를 파라미터로 받아 수정될 entity를 표현합니다.

update(
    entity(Employee::class),
)

Set clause

update statement의 set clause를 만들기 위해, set()을 사용할 수 있습니다. set()Expression을 파라미터로 받아 할당을 표현합니다. set()을 여러번 호출하는 것으로 여러 개를 할당할 수 있습니다.

set(
    path(Book::price)(BookPrice::value),
    BigDecimal.valueOf(100)
).set(
    path(Book::salePrice)(BookPrice::value),
    BigDecimal.valueOf(80)
)

Where clause

update statement의 where clause를 만들기 위해, where()를 사용할 수 있습니다. where()Predicate를 파라미터로 받아 조회 데이터의 제약을 표현합니다. where()and()의 축약어로 whereAnd()를 사용할 수 있습니다. 마찬가지로 where()or()의 축약어로 whereOr()을 사용할 수 있습니다.

where(
    path(Book::publishDate).between(
        OffsetDateTime.parse("2023-01-01T00:00:00+09:00"),
        OffsetDateTime.parse("2023-06-30T23:59:59+09:00"),
    ),
)

Delete statement

jpql()에서 deleteFrom()를 호출하는 것으로 delete statement를 만들 수 있습니다.

val query = jpql {
    deleteFrom(
        entity(Book::class),
    ).where(
        path(Book::publishDate).ge(OffsetDateTime.parse("2023-06-01T00:00:00+09:00")),
    )
}

Delete from clause

delete statement의 delete clause를 만들기 위해, deleteFrom()을 사용할 수 있습니다. deleteFrom()Entity를 파라미터로 받아 삭제할 entity를 표현합니다.

deleteFrom(
    entity(Book::class),
)

Where clause

delete statement의 where clause를 만들기 위해, where()를 사용할 수 있습니다. where()Predicate를 파라미터로 받아 조회 데이터의 제약을 표현합니다. where()and()의 축약어로 whereAnd()를 사용할 수 있습니다. 마찬가지로 where()or()의 축약어로 whereOr()을 사용할 수 있습니다.

where(
    path(Book::publishDate).between(
        OffsetDateTime.parse("2023-01-01T00:00:00+09:00"),
        OffsetDateTime.parse("2023-06-30T23:59:59+09:00"),
    ),
)

Last updated