在Jooq帮助程序类上写作。 (一旦我弄清楚了,便会添加更多特定于业务的方法...)
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调用正确的方法?
答案 0 :(得分:0)
hello\nworld
本质上是Select
,因此无法正确推断要使用的方法。
编译器解决了有关方法调用的所有问题,直到最后一刻都没有关注任何涉及到的泛型约束,因为它注意到所选方法无效,并失败并显示错误。
泛型会出现此问题,编译器将方法识别为两种不同的方法,但是当尝试解析该方法时,它可能无法根据可用数据找到正确的方法。如果您想知道为什么要查看本文,请参阅Jon Skeet的Overloading and Generic constraints。