Укажите подсказки запроса для методов поиска SimpleJpaRepository - PullRequest
1 голос
/ 02 августа 2020

Цель

Я реализую настраиваемый базовый репозиторий с целью иметь возможность указывать узлы атрибутов графов сущностей по аргументу метода вместо аннотации метода. Поэтому вместо аннотированных методов, таких как
@EntityGraph(attributePaths = ["enrollments"])
fun findByIdFetchingEnrollments(id: Long): Optional<Student>

в моих репозиториях, у меня просто есть базовый репозиторий с таким методом, как

fun findById(id: ID, vararg attributeNodes: String): Optional<T>

, который дает большую гибкость, потому что только с одним методом я могу, например, вызовите

studentRepository.findById(1L, "enrollments") 
// or
studentRepository.findById(1L, "favouriteSubjects", "favouriteTeachers")
// and others...

, где "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

}
// 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.
    */

}
@Configuration
@EnableJpaRepositories(
        "com.domain.project.repository",
        repositoryBaseClass = RepositoryImpl::class)
class ApplicationConfiguration

Проблема

Проблема в том, что я не вижу простого способа добавления подсказки javax.persistence.loadgraph к подсказкам запроса, которые SimpleJpaRepository передают в EnitityManager.find.

Я думаю, что лучший способ решить эту проблему - переопределить SimpleJpaRepository getQueryHints(), который используется всеми методами find в SimpleJpaRepository. Тогда мой код в RepositoryImpl стал бы намного проще (переопределить все методы find , и для каждого просто добавить подсказку и вызвать супер-метод). Но я не могу его переопределить, потому что класс QueryHints является закрытым для пакета.

Если свойство SimpleJpaRepository metadata было изменяемым, я мог бы также добавить к нему подсказки запросов (которые, в свою очередь, рассматриваются в методе getQueryHints()), но все его свойства доступны только для чтения, и я думаю, что иногда metadata имеет значение null (не уверен в этом, но он помечен как @Nullable).

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...