Spring JPA:如何禁用某些方法的查询创建

问题描述 投票:0回答:3

我有一个自定义存储库,声明如下(用 Kotlin 编写):

interface FooRepository : JpaRepository<Foo, Int> {
    fun findByFoo(foo: String): List<Foo>

    fun findByBar(bar: String): List<Foo> {
        //custom implementation
    }
}

data class Foo(var id: Int, var foo: String, var bar: String)

这两种方法都满足JPA存储库的命名约定,但我想自己实现第二种方法(

FooRepository.findByBar
)。如何防止 JPA 创建查询?
请注意,我的自定义实现涉及计算逻辑,因此允许自定义查询的
@Query
注释不符合我的要求。
此外,在实际情况下,这样做是必要且合理的,因此如果您试图建议“更好”的设计模式(例如将实现放在服务层等),请不要发布您的答案或评论。

java spring kotlin jpa
3个回答
3
投票

如果您希望存储库自定义方法仅委托给另一个方法,那么在接口中编写非抽象方法是可行的方法。

但在 Kotlin 中,您需要添加

-Xjvm-default=all
编译参数,否则 Spring 会认为您的方法没有主体,并且无论如何都会初始化失败。


TL;博士

我今天在 Spring/Kotlin 项目上遇到了同样的问题,这似乎是一个简单的用例,我想知道我们如何没有更多的人抱怨它。

事实证明,这是 Kotlin 默认情况下处理接口中非抽象方法的一个极端情况!

每个人都推荐的解决方案是为自定义方法创建一个单独的接口和实现,但如果您想最终委托给自动生成的方法,这种解决方案实际上并不起作用。

由于我需要相当于委托的

findByBar
,我的第一次尝试是简单地在接口方法中编写一个主体,这完全受 Kotlin 支持,最终委托给自动生成的方法。令我惊讶的是,Spring 仍然崩溃,说我需要添加一个
@Query
注释。

然后,在看到其他人在 Java 中成功使用

default
方法(例如 12)后,我尝试了一下。我用 Java 创建了同样的东西,在界面中使用了
default
方法,并且它起作用了!

由于 Kotlin 必须与 Java 一样强大,所以我认为我只需要

-Xjvm-default=all
编译器参数(完整的问题历史记录此处)只是时间问题,因此我的非抽象方法已正确生成为
default
接口方法。


0
投票

最佳实践:根据Heshan的建议,您可以将自定义接口添加到存储库接口中。您的实现将被加载(文件名带有“Impl”后缀),并且它将覆盖同名的默认方法。

扩展JpaRepository:为什么要扩展JpaRepository接口?如果您这样做,Spring 将尝试自己创建一个存储库实例。为了防止这种情况,请用 @NoRepositoryBean 注释您的存储库

interface

@NoRepositoryBean
public interface FooRepositoryCustom extends JpaRepository<Foo, Int> {
}

参考:我正在尝试使用 Spring Data Elasticsearch 做类似的事情 - 覆盖现有的存储库方法。我遵循了他们的文档,请参阅https://docs.spring.io/spring-data/elasticsearch/docs/4.1.15/reference/html/#repositories.custom-implementations


0
投票

您可以简单地创建另一个类似

FooRepositoryCustom
的接口,并为其创建一个实现类 (
FooRepositoryCustomImpl
),并在该
FooRepositoryCustomImpl
类上进行实现,并将
FooRepositoryCustom
接口扩展到您的
FooRepository
接口。

FooRepositoryCustom

public interface FooRepositoryCustom {
    fun findByBar(bar: String): List<Foo>;
}

FooRepositoryCustomImpl

public class FooRepositoryCustomImpl implements FooRepositoryCustom {
    @Override
    public fun findByBar(bar: String): List<Foo> {
          //your implementation goes here
    }
}

FooRepository

interface FooRepository : JpaRepository<Foo, Int>, FooRepositoryCustom {

}
© www.soinside.com 2019 - 2024. All rights reserved.