在线时间:8:00-16:00
迪恩网络APP
随时随地掌握行业动态
扫描二维码
关注迪恩网络微信公众号
开源软件名称(OpenSource Name):consoleau/kotlin-jpa-specification-dsl开源软件地址(OpenSource Url):https://github.com/consoleau/kotlin-jpa-specification-dsl开源编程语言(OpenSource Language):Kotlin 93.4%开源软件介绍(OpenSource Introduction):Spring Data JPA Specification DSL for KotlinThis library provides a fluent DSL for querying spring data JPA repositories using spring data Specifications (i.e. the JPA Criteria API), without boilerplate code or a generated metamodel. Hat tip to Mike Buhot for the initial implementation. Quick Startrepositories {
jcenter()
}
dependencies {
compile("au.com.console:kotlin-jpa-specification-dsl:2.0.0")
} Exampleimport au.com.console.jpaspecificationdsl.* // 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) })
}
} Advanced UsageFor more complex and dynamic queries it's good practice to create functions that use the DSL to make queries more readable, and to allow for their composition in complex dynamic queries. fun hasName(name: String?): Specification<TvShow>? = name?.let {
TvShow::name.equal(it)
}
fun availableOnNetflix(available: Boolean?): Specification<TvShow>? = available?.let {
TvShow::availableOnNetflix.equal(it)
}
fun hasReleaseDateIn(releaseDates: List<String>?): Specification<TvShow>? = releaseDates?.let {
TvShow::releaseDate.`in`(releaseDates)
}
fun hasKeywordIn(keywords: List<String>?): Specification<TvShow>? = keywords?.let {
or(keywords.map(::hasKeyword))
}
fun hasKeyword(keyword: String?): Specification<TvShow>? = keyword?.let {
TvShow::synopsis.like("%$keyword%")
} These functions can be combined with and() and or() for complex nested queries: val shows = tvShowRepo.findAll(
or(
and(
availableOnNetflix(false),
hasKeywordIn(listOf("Jimmy"))
),
and(
availableOnNetflix(true),
or(
hasKeyword("killer"),
hasKeyword("monster")
)
)
)
) Or they can be combined with a service-layer query DTO and mapping extension function /**
* 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(),
val releaseDates: 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(): Specification<TvShow> = and(
hasName(name),
availableOnNetflix(availableOnNetflix),
hasKeywordIn(keywords),
hasReleaseDateIn(releaseDates)
) for powerful dynamic queries: val query = TvShowQuery(availableOnNetflix = false, keywords = listOf("Rick", "Jimmy"))
val shows = tvShowRepo.findAll(query.toSpecification()) For more details, refer to How it worksThis DSL builds on Spring Data's Specifications abstraction, sprinkling some Kotlin sugar over it to remove the boilerplate and the need to generate a metamodel. The code fun <T, R> KProperty1<T, R?>.equal(x: R): Specification<T> = spec { equal(it, x) } This is a bit dense, but makes sense when it's broken down:
This is implemented using a private helper function private fun <T, R> KProperty1<T, R?>.spec(makePredicate: CriteriaBuilder.(path: Path<R>) -> Predicate): Specification<T> =
this.let { property -> where { root -> makePredicate(root.get(property)) } } This uses the The code converts a Once it has a The Contributing to the ProjectIf you'd like to contribute code to this project you can do so through GitHub by forking the repository and generating a pull request. By contributing your code, you agree to license your contribution under the terms of the Apache License v2.0. LicenseCopyright 2016 RES INFORMATION SERVICES PTY LTD Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0 Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License. |
2023-10-27
2022-08-15
2022-08-17
2022-09-23
2022-08-13
请发表评论