You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Kotlin扩展函数未调用Hibernate/JPA中重写的findById方法问题

问题原因及解决方案

核心原因:Kotlin扩展函数的静态分发机制

Kotlin扩展函数属于静态分发,编译器会根据调用时接收者的静态类型(而非实际运行时类型)解析调用的方法:

  • 直接调用fooRepository.findById(id)时,fooRepository的静态类型是你的自定义Repository接口(如FooRepository),Spring生成的代理类实现了该接口,因此会触发你重写的带@Query的findById方法。
  • 你的findByIdOrNull是定义在CrudRepository<T, ID>上的扩展函数,调用fooRepository.findByIdOrNull(id)时,编译器会将扩展函数内部的findById解析为CrudRepository接口的默认实现(未包含deletedAt is null的过滤逻辑),而非你在自定义Repository中重写的方法,因此会查询到已标记删除的实体。

解决方案

方案1:将扩展函数定义在自定义Repository接口上

把扩展函数的接收者改为具体的自定义Repository接口,让编译器解析到你重写的findById方法:

fun FooRepository.findByIdOrNull(id: UUID): Foo? = findById(id).orElse(null)

方案2:定义通用BaseRepository接口并扩展

如果多个自定义Repository都需要该扩展功能,可以先定义通用BaseRepository接口,让所有自定义Repository继承它,再将扩展函数定义在BaseRepository上:

// 定义通用BaseRepository
interface BaseRepository<T, ID> : CrudRepository<T, ID> {
    override fun findById(id: ID): Optional<T>
}

// 自定义Repository继承BaseRepository
interface FooRepository : BaseRepository<Foo, UUID> {
    @Query("from Foo v where v.id = :id and v.deletedAt is null")
    override fun findById(id: UUID): Optional<Foo>
}

// 扩展函数定义在BaseRepository上
fun <T, ID> BaseRepository<T, ID>.findByIdOrNull(id: ID): T? = findById(id).orElse(null)

这样任意自定义Repository调用findByIdOrNull时,都会触发各自重写的findById方法。


内容的提问来源于stack exchange,提问作者FeXseven

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.07 18:42:22