为 SimpleJpaRepository 查找方法指定查询提示

Joã*_* Fé 5 spring spring-data-jpa kotlin

目标

我正在实现一个自定义基础存储库,其目标是能够通过方法参数而不是方法注释来指定实体图的属性节点。因此,不要使用带注释的方法,例如
@EntityGraph(attributePaths = ["enrollments"])
fun findByIdFetchingEnrollments(id: Long): Optional<Student>
Run Code Online (Sandbox Code Playgroud)

在我的存储库中,我只有一个基本存储库,其方法如下

fun findById(id: ID, vararg attributeNodes: String): Optional<T>
Run Code Online (Sandbox Code Playgroud)

这提供了很大的灵活性,因为我只能使用一种方法,例如,调用

studentRepository.findById(1L, "enrollments") 
// or
studentRepository.findById(1L, "favouriteSubjects", "favouriteTeachers")
// and others...
Run Code Online (Sandbox Code Playgroud)

其中"enrollments""favouriteSubjects"、 和"favouriteTeachers"默认情况下是延迟获取实体字段,但有时需要急切地获取(以避免LazyInitializationException

我拥有的

这些是我的课程:
// Base repository interface. All my repositories will extend this interface

@NoRepositoryBean
interface Repository<T, ID> : JpaRepository<T, ID> {

    fun findById(id: ID, vararg attributeNodes: String): Optional<T>
    
    // other find methods

}
Run Code Online (Sandbox Code Playgroud)
// Custom base class. Inherits SimpleJpaRepository

class RepositoryImpl<T, ID>(
        val entityInformation: JpaEntityInformation<T, Any?>,
        val em: EntityManager
) : SimpleJpaRepository<T, ID>(entityInformation, em), Repository<T,ID> {

    // This is basically a copy-paste of SimpleJpaRepository findById method implementation... 
    override fun findById(id: ID, vararg attributeNodes: String): Optional<T> {
    
        Assert.notNull(id, "The given id must not be null!")

        /*
        Because 'repositoryMethodMetadata!!.queryHints' is read-only, I have to create a new Map,
        put all the queryHints entries in it and put the 'javax.persistence.loadgraph' hint.
         */

        val graph = em.createEntityGraph(entityInformation.javaType)
        graph.addAttributeNodes(*attributeNodes)

        val hints: MutableMap<String, Any?> = HashMap()
        hints.putAll(repositoryMethodMetadata!!.queryHints)

        hints["javax.persistence.loadgraph"] = graph

        if (repositoryMethodMetadata == null) {
            return Optional.ofNullable(em.find(domainClass, id, hints))
        }

        val type = repositoryMethodMetadata!!.lockModeType

        return Optional.ofNullable(
                if (type == null) em.find(domainClass, id, hints)
                else em.find(domainClass, id, type, hints)
        )
    }

    /* 
    In order to implement the other find methods the same kind of copy-paste implementations
    needs to be done, which shouldn't be necessary but I'm not seeing how.
    */

}
Run Code Online (Sandbox Code Playgroud)
@Configuration
@EnableJpaRepositories(
        "com.domain.project.repository",
        repositoryBaseClass = RepositoryImpl::class)
class ApplicationConfiguration
Run Code Online (Sandbox Code Playgroud)

问题

问题是我没有看到将 javax.persistence.loadgraph 提示添加到 SimpleJpaRepository 传递给 EnitityManager.find 的查询提示中的简单方法。

我认为解决这个问题的最好方法是重写 SimpleJpaRepositorygetQueryHints() 方法,该方法SimpleJpaRepository. 然后我的代码RepositoryImpl将变得更加简单(覆盖所有查找方法,并且为每个方法添加提示并调用超级方法)。但我无法覆盖它,因为QueryHints类是包私有的。

如果 SimpleJpaRepositorymetadata属性是可变的,我还可以向其添加查询提示(依次在getQueryHints()方法中考虑),但它的所有属性都是只读的,我认为有时metadata为 null(对此不确定,但它被标记为@Nullable)。