Mamut
Mamut

Reputation: 313

Why Hibernate Lazy loading acts different in Kotlin?

Here is a simple example of @OneToOne entity mapping using Java 11, Spring Boot 2.4.5 and Hibernate 5.4.29.

In Java implementation Lazy loading works fine - only Post entity is loaded:

select id, details_id from post

Here is the same code in Kotlin. It produces following SQL:

select id, details_id from post

select pd.id, p.id, p.details_id
from post_details pd
    left outer join post p on pd.id = p.details_id
where pd.id = ?

select p.id, p.details_id from post p
where p.details_id = ?

I do not understand what is wrong here. Mapping is the same but LAZY is ignored. Moreover the bidirectional association is loaded twice - one SELECT from each side.


SOLUTION UPDATE

In addition to Lukes's solution I would like to point out one Kotlin confusion: kotlin-jpa plugin is surprisingly not enough to make JPA/Hibernate work properly. We had to configure kotlin-spring plugin (which is a wrapper for all-open plugin) and configure it to make @Entity open. This way, Hibernate can finally create proxy allowing lazy loading.

Upvotes: 3

Views: 1547

Answers (2)

Phill Watson
Phill Watson

Reputation: 41

I've also noticed that the Kotlin scope function with() will perform eager loading of lazy-loaded properties on the class.

@OneToMany(mappedBy = "book", cascade = [CascadeType.ALL], fetch = FetchType.LAZY, orphanRemoval = true)
open var chapters: MutableSet<Chapter> = mutableSetOf()

Using the with() function

with(bookRepository.findById(bookId)) {
  assertNotNull(this)
}

The chapters will be loaded eagerly. Whereas the following doesn't:

val book: Book? = bookRepository.findById(bookId)
assertNotNull(book)

Upvotes: 0

Luke
Luke

Reputation: 516

This is caused by kotlin classes. In order to fix it do as follow:

In your build.gradle plugins section:

plugins {
    kotlin("plugin.spring") version <kotlinVersion>
    kotlin("plugin.jpa") version <kotlinVersion>
}

and at bottom of file

allOpen {
    annotation("javax.persistence.Entity")
    annotation("javax.persistence.MappedSuperclass")
    annotation("javax.persistence.Embeddable")
}

this should fix the problem

Upvotes: 4

Related Questions