Как избежать инициализации Hibernate-прокси, когда нужен только идентификатор объекта - PullRequest
0 голосов
/ 25 ноября 2018

Для отношения @ManyToOne в сущности JPA меня интересует только фактическая ссылка на идентификатор, а не извлечение всей модели, связанной с отношением.

Возьмем, к примеру, следующие сущности Kotlin JPA:

@Entity
class Continent(
        @Id
        var id: String,
        var code: String,
        var name: String
) : Comparable<Continent> {

    companion object {
        private val COMPARATOR = compareBy<Continent> { it.id }
    }

    override fun compareTo(other: Continent): Int {
        return COMPARATOR.compare(this, other)
    }
}

@Entity
class Country(
        @Id
        var id: String,
        var alpha2Code: String,
        var alpha3Code: String,
        var name: String,
        @ManyToOne(fetch = FetchType.LAZY)
        @JoinColumn(name = "continent_id")
        var continent: Continent

) : Comparable<Country> {

    companion object {
        private val COMPARATOR = compareBy<Country> { it.id }
    }

    override fun compareTo(other: Country): Int {
        return COMPARATOR.compare(this, other)
    }
}

Теперь, когда я получаю доступ к country.continent.id из своего кода Kotlin, полный Continent фактически запрашивается из базы данных.Это излишне, так как меня интересует только Continent.id.

Я пытался добавить @Access(AccessType.PROPERTY), например:

@Entity
class Continent(
        @Id
        @Access(AccessType.PROPERTY)
        var id: String,

, но это не имеет значения.Целое Continent все еще запрашивается из базы данных.

Я попробовал @Access(AccessType.PROPERTY), как было упомянуто в других сообщениях (например, Hibernate один-к-одному: getId () без извлечения всего объекта), но я уже заметил смешанные отзывы по этому поводу.

Я использую Hibernate 5.3.7.Final с Kotlin 1.3.0.

Интересно, 1) подход @Access(AccessType.PROPERTY) является правильным и 2) Должно ли это также работать с Kotlin?Может быть, способ, которым Kotlin генерировал код Java, вызывает проблему?

UPDATE

Я создал простой тестовый проект, доказывающий, что континент запрашивается.https://github.com/marceloverdijk/hibernate-proxy-id

Проект содержит простой тест для извлечения country.continent.id, и ведение журнала SQL включено.Из журнала видно, что континент запрашивается .

ОБНОВЛЕНИЕ 2

Я создал https://youtrack.jetbrains.net/issue/KT-28525 для этого.

1 Ответ

0 голосов
/ 25 ноября 2018

Это поведение определяется спецификацией JPA, которая требует извлечения ассоциации при доступе к любому свойству, даже к идентификатору.

Традиционно, Hibernate не инициализирует прокси-объект сущности при доступе к его идентификатору, но это поведениене соответствовал спецификации JPA, поэтому возникла необходимость явного отключения этой стратегии соответствия JPA.

Фактически я создал эти два тестовых примера в Hibernate ORM, и все работает, как и ожидалось:

По умолчанию прокси-сервер не инициализируется при доступе только к идентификатору.

Это тест:

Continent continent = doInJPA( this::entityManagerFactory, entityManager -> {
    Country country = entityManager.find( Country.class, 1L );

    country.getContinent().getId();

    return country.getContinent();
} );

assertEquals( 1L, (long) continent.getId());

assertProxyState( continent );

По умолчанию это ожидаемое поведение:

protected void assertProxyState(Continent continent) {
    try {
        continent.getName();

        fail( "Should throw LazyInitializationException!" );
    }
    catch (LazyInitializationException expected) {

    }
}

Однако, если мы переключимся на совместимость с JPA, то:

<property name="hibernate.jpa.compliance.proxy" value="false"/>

Вот что мы получаем:

protected void assertProxyState(Continent continent) {
    assertEquals( "Europe", continent.getName() );
}

Следовательно, все работает как положено.

Проблема связана с Kotlin или Spring Data JPA.Вам нужно дополнительно изучить его и понять, почему прокси инициализируется.

Скорее всего, это из-за реализации toString или compare, добавленной к сущности Continent.

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