为什么 FetchType.LAZY 在 Hibernate/JPA 中不起作用?

mle*_*ter 8 hibernate jpa kotlin

我有以下对象(简化):

@Entity
@Table(name = "delivery_addresses")
data class DeliveryAddress (
        val street: String
) {

    @ManyToOne(fetch=FetchType.LAZY)
    lateinit var user: User
}
Run Code Online (Sandbox Code Playgroud)

当我通过 ID 查询对象时

val deliveryAddress = deliveryAddressService.findById(1)
Run Code Online (Sandbox Code Playgroud)

哪个

val deliveryAddress = deliveryAddressService.findById(1)
Run Code Online (Sandbox Code Playgroud)

我可以看到执行了以下查询:

override fun findById(deliveryAddressId: Long): DeliveryAddress? {
    return deliveryAddressRepository.findById(deliveryAddressId).orElse(null) // JpaRepository
}
Run Code Online (Sandbox Code Playgroud)

我怎样才能使FetchType.LAZY工作作为例外(也@Basic(fetch = FetchType.LAZY)不适合我)?

mle*_*ter 6

最后我能够弄清楚。该问题与 kotlin 数据类有关(请参阅KT-28525

不应将数据类与 spring-data-jpa 一起使用。引用自kotlin spring-guide

在这里,我们不使用具有 val 属性的数据类,因为 JPA 并非设计为与不可变类或由数据类自动生成的方法一起使用。如果您使用其他 Spring Data 风格,它们中的大多数都旨在支持此类构造,因此在使用 Spring Data MongoDB、Spring Data JDBC 等时,您应该使用数据类 User(val login: String, ...?) 等类。

为了使延迟获取按预期工作,实体应该是开放的。我的解决方案:

build.gradle.kts:

plugins {
  kotlin("plugin.allopen") version "1.3.61"
}

allOpen {
  annotation("javax.persistence.Entity")
  annotation("javax.persistence.Embeddable")
  annotation("javax.persistence.MappedSuperclass")
}
Run Code Online (Sandbox Code Playgroud)