๋ค์ด๊ฐ๊ธฐ ์์
ํ์ฌ QueryDSL 5.0.0 ๋ฒ์ ์ ๊ธฐ๋ฐ์ผ๋ก ํ๋ก์ ํธ ๊ฐ๋ฐ์ ์งํํ๊ณ ์๋๋ฐ, ๋ณต์กํ ์ฐ๊ด๊ด๊ณ๋ฅผ ๊ฐ์ง๋ ํ ์ด๋ธ์ JPA Mapping ์ ์ฌ์ฉํด ๋น์ฆ๋์ค ๋ก์ง์ ์ํํ ๊ฒฝ์ฐ ๋๋ฌด ๋ง์ ์ฟผ๋ฆฌ๋ฅผ ์์ฒญํ๊ฒ ๋์ด ๋ถํ์ํ ์์์ ์ฌ์ฉํ๋ ๋ฌธ์ ๊ฐ ์์๋ค. ์ด๋ฅผ ํด๊ฒฐํ๊ธฐ ์ํด @Query ์ ๋ ธํ ์ด์ ์ ์ฌ์ฉํด ๋ ํผ์งํ ๋ฆฌ์ ์กฐํ ๋ฉ์๋๋ฅผ ๊ตฌํํ๋ ๊ฒ์ ๊ณ ๋ ค ํ์ง๋ง ๋ค์๊ณผ ๊ฐ์ ์ด์ ๋ก ๋ฐ๋ คํ๋ค.
- ์ฌ๋ฌ ํ ์ด๋ธ์ ํ ๋ฒ์ ์กฐํํด ํ๋์ ๋๋ฉ์ธ ํด๋์ค๋ก ์ฌ๊ตฌ์ฑํด์ผ ํ๋ฉฐ, ์ฌ๋ฌ ์กฐ๊ฑด์ ๊ฒฐ๊ณผ๋ฅผ GroupBy ํ์ฌ ์๋ฒ ๋๋ ํด๋์ค์ ํ๋์ ํ ๋นํด์ผ ํ๋ ์ํฉ์์ @Query ์ ๋ ธํ ์ด์ ์ ๊ตฌํ์ด ์ด๋ ค์ธ ๊ฒ์ด๋ผ๊ณ ์๊ฐํ๋ค.
- ํน์ ์ํฐํฐ์ ๋ ํผ์งํ ๋ฆฌ์ @Query ๋ฅผ ์ฌ์ฉํด ์กฐํ ๋ฉ์๋๋ฅผ ๊ตฌํํ๋ ๊ฒ์ ํด๋น ๋ ํผ์งํ ๋ฆฌ์ ๋ถํ์ํ ์ฑ ์์ ๋ถ์ฌํ๋ค๊ณ ์๊ฐํ๋ค.
์ด๊ฐ์ ์ด์ ๋ก QueryDSL ์์ ์ ๊ณตํ๋ ๊ฒฐ๊ณผ ์งํฉ ํจ์๋ฅผ ์ ๊ทน ํ์ฉํ์ฌ ์ฌ๋ฌ ํ ์ด๋ธ์ ์กฐํํ๊ณ ๊ฐ ์กฐ๊ฑด์ ๋ง๋ ๊ฒฐ๊ณผ๋ฅผ ํ๋์ ๋๋ฉ์ธ ํด๋์ค์ ๋งตํํ๋ ์ฝ๋๋ฅผ ์์ฑํ๋ค.
@QueryProjection
๋งตํํ ๋๋ฉ์ธ ํด๋์ค์ ์์ฑ์์ @QueryProjection ์ ์ฉํด ๋๋ฉ์ธ ํด๋์ค์ QClass ์์ฑ์ ์์ฑํ ์ ์๋๋ก ํ๋ค. Projections.bean() / Projections.fields() ์ ๊ฐ์ ํจ์๋ฅผ ์ฌ์ฉํ ์ ์์์ง๋ง, ์ด๋ค ์ด์ ์์์ธ์ง ๋งตํ์ด ๋์ง ์์๋ค. (java.lang.IllegalArgumentException: argument type mismatch
๋ฐ์)
// ์ ํ ๋๋ฉ์ธ ํด๋์ค
data class Product @QueryProjection constructor(
val categoryId: String,
val categoryName: String,
val productId: String,
val name: String,
val price: Int,
val keywords: List<Keyword>
)
// ์ ํ ํค์๋ ๋๋ฉ์ธ ํด๋์ค
data class Keyword @QueryProjection constructor(
val keywordId: String,
val keyword: String,
val productId: String
)
transform(...)
PersistenceAdapter ์์ ๊ตฌํํ๊ณ ์ ํ๋ Port ์ ํจ์์ QueryFactory ๋ฅผ ์ฌ์ฉํด ๋๋ฉ์ธ ํด๋์ค๋ก ๋ฐ๋ก ๋ฆฌํดํด์ฃผ๋๋ก ํ๋ค.
๋ง๋ค๋ฉด์ ๋ฐฐ์ฐ๋ ํด๋ฆฐ ์ํคํ
์ณ ์์๋ DomainMapper ๋ฅผ ์ด์ฉํด ์ฌ๋ฌ ํ
์ด๋ธ์ ์กฐํ ๊ฒฐ๊ณผ๋ฅผ ๋๋ฉ์ธ ํด๋์ค์ ๋งตํํด์ฃผ๋๋ก ํ๋๋ฐ, ํด๋น ๊ณผ์ ์์ ์์์ ์ธ๊ธํ ๋ถํ์ํ ์กฐํ ์ฟผ๋ฆฌ ์์ฒญ ๋ฐ ๋ฆฌ์์ค ์ฌ์ฉ ๋ฌธ์ ๊ฐ ๋ฐ์ํ๊ธฐ ๋๋ฌธ์ ์ด๋ฒ ๋น์ฆ๋์ค ๋ก์ง์์๋ ์ ์ธํ๋๋ก ํ๋ค.
// QClass static import
@PersistenceAdapter
class ProductPersistenceAdapter(
private val queryFactory: JpaQueryFactory
) : GetProductPort {
override fun getProducts(categoryId: String): List<Product> {
return queryFactory
.from(eCategory)
.join(eProduct).on(eProduct.categoryId.eq(eCategory.id))
.leftJoin(eKeyword).on(eKeyword.productId.eq(eProduct.id))
.where(eCategory.id.eq(categoryId))
.transform(
groupBy(eCategory.id)
.list(
QProduct(
eCategory.id,
eCategory.name,
eProduct.id,
eProduct.name,
eProduct.price,
list(
QKeyword(
eKeyword.id,
eKeyword.keyword,
eKeyword.productId
)
)
)
)
)
}
}
NoSuchMethodError
์์ ๊ฐ์ด ์ฝ๋๋ฅผ ์์ฑํ๊ณ ํ ์คํธ ์ฝ๋๋ฅผ ์คํํ๋ ๋ค์๊ณผ ๊ฐ์ ์๋ฌ๊ฐ ๋ฐ์ํ๋ค.
Caused by: java.lang.NoSuchMethodError: 'java.lang.Object org.hibernate.ScrollableResults.get(int)'
ํด๋น ์๋ฌ๋ฅผ ๋๋ฒ๊น ํด๋ณด๋ ์กฐํํ ๋ฐ์ดํฐ๋ค์ ๋๋ฉ์ธ ํด๋์ค์ QClass ์์ฑ์์ ์๊ท๋จผํธ๋ก ์ค์ ํ๋ ๊ณผ์ ์์ ๋ฐ์ํ๋ ๋ฌธ์ ์๊ณ , ๋ค๋ฅธ ํ๋๋ค์ ๊ด์ฐฎ์๋๋ฐ Left Join ์ผ๋ก ์กฐํํ Keyword ๋ฐ์ดํฐ๋ฅผ List ๋ก ๋งตํํ๋ ์ค์ ๋ฐ์ํ๋ ๊ฒ์ผ๋ก ํ์ธ๋๋ค.
์ด๋ฅผ ํด๊ฒฐํ๊ธฐ ์ํด ๊ตฌ๊ธ๋ง ํด๋ณธ ๊ฒฐ๊ณผ, ๋ค์์ ์ด์๋ฅผ ์ฐพ์ ์ ์์๋ค.
'Programming > Spring' ์นดํ ๊ณ ๋ฆฌ์ ๋ค๋ฅธ ๊ธ
[Spring Security] @AuthenticationPrincipal Test Trouble Shooting (0) | 2023.04.08 |
---|---|
Criteria API (0) | 2023.01.28 |
Spring Bean / IoC Container / DI (1) | 2023.01.21 |
JPA / Persistence Context / Transactional (2) | 2023.01.14 |
Spring | Spring Framework ? (0) | 2020.08.02 |