撰写Jooq Helper类。(在我弄清楚之后,将添加更多业务特定的方法...)
import org.jooq.*
import org.springframework.stereotype.Repository
import javax.inject.Inject
import javax.inject.Provider
/**A helper class facilitating database manipulations.
* Uses jOOQ for its manipulations.
* Relies on the application context being properly initialized s.t. Spring creates and injects the correct
* [DSLContext].*/
@Repository
class DatabaseManipulator{
private val provider: Provider<DSLContext>
private val create:DSLContext
get() = provider.get()
@Inject
constructor(provider: Provider<DSLContext>) {
this.provider = provider
}
/**Executes non-[Select]-type SQL queries on the database.
* Does not perform any kind of checks and trusts the client to know what they're doing.
* @param query the query to be executed.
*
* @return depending on the type of the [query]:
* <ul>
* <li> Delete : the number of deleted records</li>
* <li> Insert : the number of inserted records</li>
* <li> Merge : result may be meaningless</li>
* <li> Truncate : result may be meaningless</li>
* <li> Update : the number of updated records</li>
* </ul>
*/
fun execute(query:DSLContext.()-> Query):Int{
return create.query().execute()
}
/**Executes [Select]-type [query] and returns its result*/
fun <T:Record> execute(query:DSLContext.()->Select<T>):Result<T>{
return create.query().fetch()
}
}
目前为止,一切都很好。现在让我们添加一些测试。
@RunWith(SpringJUnit4ClassRunner::class)
@SpringBootTest
@Transactional
class DatabaseManipulatorIT {
@Inject
private lateinit var manipulate:DatabaseManipulator
@Inject
private lateinit var em:EntityManager
@Test
fun executeSelectQuery() {
//given
val expectedNumberOfOrganizations = em.createQuery("SELECT COUNT (o) FROM Organization o")
.singleResult as Long
//when
val reportedNumberOfOrganizations = manipulate.execute {
selectCount().from(ORGANIZATION)
}.first().value1().toLong()
//then
assertThat(reportedNumberOfOrganizations).isEqualTo(expectedNumberOfOrganizations)
}
@Test
fun executeNonSelectQuery() {
//given
val expectedNumberOfDeletions = em.createQuery(
"SELECT COUNT (o) FROM Organization o WHERE o.usageCreditLimited = true"
).singleResult as Long
//when
val actualNumberOfDeletions = manipulate.execute {(
deleteFrom(ORGANIZATION)
.where(ORGANIZATION.USAGECREDITLIMITED.eq(true))
) as Query
}
//then
assertThat(actualNumberOfDeletions).isEqualTo(expectedNumberOfDeletions)
}
}
因为这个代码无法编译。
Error:(50, 50) Kotlin: Type inference failed: fun <T : Record> execute(query: DSLContext.() -> Select<T>): Result<T>
cannot be applied to
(DSLContext.() -> DeleteConditionStep<OrganizationRecord!>!)
Error:(50, 58) Kotlin: Type mismatch: inferred type is DSLContext.() -> DeleteConditionStep<OrganizationRecord!>! but DSLContext.() -> Select<???> was expected
别开玩笑,我不是要你使用那种方法,我是想让你用另一种。
我们来明确一下:
//when
val actualNumberOfDeletions = manipulate.execute {(
deleteFrom(ORGANIZATION)
.where(ORGANIZATION.USAGECREDITLIMITED.eq(true))
) as Query
}
仍然无法编译第二个测试用例,因为
Error:(50, 50) Kotlin: Type inference failed: fun <T : Record> execute(query: DSLContext.() -> Select<T>): Result<T>
cannot be applied to
(DSLContext.() -> Query)
Error:(50, 58) Kotlin: Type mismatch: inferred type is DSLContext.() -> Query but DSLContext.() -> Select<???> was expected
我该如何让Kotlin调用正确的方法?
Select
本质上是一个Query
,所以你想使用的方法无法正确解析。尝试更改方法签名,使其不依赖于传递的参数来解析该方法。 - Keivan EsbatiSelect
是一个Query
,反过来却不成立。那么为什么非Select
查询不能与非Select
方法绑定呢? - User1291fetch
(生成结果)和execute
(生成更新计数)。为什么要同时使用相同的术语呢?在某些情况下,重载比方便更容易出现问题...请注意,您可能希望引用ResultQuery<T>
而不是Select<T>
以获得更通用的解决方案。 - Lukas Ederfun q() : DSLContext.() -> Query = { ... }
或fun s() : DSLContext.() -> Select
并将这些函数传递给您的execute
,它可能会(尚未测试)... 甚至以下内容也可能有效:fun <T> dsl(dsl : DSLContext.() -> T) = dsl
并调用manipulate.execute(dsl { ... })
... 它能工作吗?;-) 也许您迟早会在这里结束:Kotlin 中的类型擦除是如何工作的? 或者在这里:Kotlin 类型擦除 - ... 泛型 - Roland