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์„ ํŒŒ๋ผ๋ฏธํ„ฐ๋กœ ๋ฐ›์•„ ํ”„๋กœ์ ์…˜์„ ํ‘œํ˜„ํ•ฉ๋‹ˆ๋‹ค. ๋งŒ์•ฝ ํ•˜๋‚˜์˜ Expression๋งŒ select()์— ๋„˜์–ด์˜จ๋‹ค๋ฉด ํƒ€์ž… ์ถ”๋ก ์œผ๋กœ 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()์€ Entity์™€ Join์„ ํŒŒ๋ผ๋ฏธํ„ฐ๋กœ ๋ฐ›์•„ ์–ด๋–ค 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