Kotlin (및 Spring Data JPA)을 사용하는 사용자를 위해 우리는 Kotlin JPA Specification DSL library을 오픈 소스로 사용하여 JPA 저장소에 대한 유형 안전 동적 쿼리를 만들 수 있습니다.
스프링 데이터의 JpaSpecificationExecutor
(예 : JPA criteria queries)을 사용하지만, 상용구 또는 생성 된 메타 모델이 필요하지 않습니다.
readme에는 내부적으로 작동하는 방법에 대한 자세한 내용이 나와 있지만 여기에는 빠른 소개를위한 관련 코드 예제가 있습니다. 더 복잡하고 동적 쿼리의
import au.com.console.jpaspecificationsdsl.* // 1. Import Kotlin magic
////
// 2. Declare JPA Entities
@Entity
data class TvShow(
@Id
@GeneratedValue
val id: Int = 0,
val name: String = "",
val synopsis: String = "",
val availableOnNetflix: Boolean = false,
val releaseDate: String? = null,
@OneToMany(cascade = arrayOf(javax.persistence.CascadeType.ALL))
val starRatings: Set<StarRating> = emptySet())
@Entity
data class StarRating(
@Id
@GeneratedValue
val id: Int = 0,
val stars: Int = 0)
////
// 3. Declare JPA Repository with JpaSpecificationExecutor
@Repository
interface TvShowRepository : CrudRepository<TvShow, Int>, JpaSpecificationExecutor<TvShow>
////
// 4. Kotlin Properties are now usable to create fluent specifications
@Service
class MyService @Inject constructor(val tvShowRepo: TvShowRepository) {
fun findShowsReleasedIn2010NotOnNetflix(): List<TvShow> {
return tvShowRepo.findAll(TvShow::availableOnNetflix.isFalse() and TvShow::releaseDate.equal("2010"))
}
/* Fall back to spring API with some extra helpers for more complex join queries */
fun findShowsWithComplexQuery(): List<TvShow> {
return tvShowRepo.findAll(where { equal(it.join(TvShow::starRatings).get(StarRating::stars), 2) })
}
}
가 쿼리를 더 읽기 쉽게하기 위해 DSL을 사용하는 함수를 작성하는 것이 좋습니다, 그리고 복잡한 동적 쿼리에서의 구성을 허용하기 위해 (당신이 QueryDSL에 대해서와 같은).
val shows = tvShowRepo.findAll(
or(
and(
availableOnNetflix(false),
hasKeywordIn(listOf("Jimmy"))
),
and(
availableOnNetflix(true),
or(
hasKeyword("killer"),
hasKeyword("monster")
)
)
)
)
아니면이 서비스 계층 쿼리 DTO 및 매핑 확장 기능
/**
* A TV show query DTO - typically used at the service layer.
*/
data class TvShowQuery(
val name: String? = null,
val availableOnNetflix: Boolean? = null,
val keywords: List<String> = listOf()
)
/**
* A single TvShowQuery is equivalent to an AND of all supplied criteria.
* Note: any criteria that is null will be ignored (not included in the query).
*/
fun TvShowQuery.toSpecification(): Specifications<TvShow> = and(
hasName(name),
availableOnNetflix(availableOnNetflix),
hasKeywordIn(keywords)
)
와 결합 될 수있다 :
fun hasName(name: String?): Specifications<TvShow>? = name?.let {
TvShow::name.equal(it)
}
fun availableOnNetflix(available: Boolean?): Specifications<TvShow>? = available?.let {
TvShow::availableOnNetflix.equal(it)
}
fun hasKeywordIn(keywords: List<String>?): Specifications<TvShow>? = keywords?.let {
or(keywords.map { hasKeyword(it) })
}
fun hasKeyword(keyword: String?): Specifications<TvShow>? = keyword?.let {
TvShow::synopsis.like("%$keyword%")
}
이러한 기능은 복잡한 중첩 된 쿼리에 대한 and()
및 or()
와 결합 될 수있다 강력한 동적 쿼리를위한
:
val query = TvShowQuery(availableOnNetflix = false, keywords = listOf("Rick", "Jimmy"))
val shows = tvShowRepo.findAll(query.toSpecification())
JpaSpecificationExecutor
은 페이징을 지원하므로 페이지 가능하고 형식이 안전한 동적 쿼리를 얻을 수 있습니다!
감사합니다. 좋은 해결책처럼 보입니다. – greyfox
@Alan Hay, QueryDsl + Spring Data Repository를 사용할 때 Join Fetch (보통 저는 LAZY에서 대부분의 관계가 있습니다)를 지정할 수 있습니까? – sendreams