简体   繁体   English

Kotlin JPA Lazy RestAPI 不受尊重

[英]Kotlin JPA Lazy RestAPI not respected

I have a project in Java and i am converting to Kotlin, but the entities with relations and mapping @ManytoOne they are with problems.我有一个 Java 项目,我正在转换为 Kotlin,但是具有关系和映射 @ManytoOne 的实体存在问题。 The entities they are using mapping fecht type LAZY, aren't they respecting the LAZY and executing the query.他们使用映射 fecht 类型 LAZY 的实体,他们是否尊重 LAZY 并执行查询。

Exemple:例子:

Entity father:实体父亲:

@Entity
@Table(name = "TIPOSITUACAO")
data class TipoSituacao (
    @Id
    @Column(name = "ID")
    val id: Long? = null,

    @Column(name = "DESCRICAO")
    val descricao: String? = null
)

Entity son:实体儿子:

@Entity
@Table(name = "SITUACAO")
data class Situacao (

    @Id
    @Column(name = "ID")
    val id: Long,

    @Column(name = "DESCRICAO")
    val descricao: String = "",

    @Column(name = "TIPOSITUACAO_ID")
    val tipoSituacaoId: Long? = null,

    @ManyToOne(fetch = FetchType.LAZY, optional = true)
    @JoinColumn(name = "TIPOSITUACAO_ID", referencedColumnName = "ID", insertable = false, updatable = false)
    val tipoSituacao: TipoSituacao? = null
)

My endpoint:我的终点:

@RequestMapping("/api")
@RestController
class EndPoints {
    @Autowired
    private val situacaoRepository: SituacaoRepository? = null

   val situacao: List<Situacao>
        @GetMapping(value = ["/situacao"])
        get() = situacaoRepository!!.findAll()
}

return:返回:

[
    {
        "id": 1,
        "descricao": "SITUACAO 1.1",
        "tipoSituacaoId": 1,
        "tipoSituacao": {
            "id": 1,
            "descricao": "TIPO SITUACAO 1"
        }
    },
    {
        "id": 2,
        "descricao": "SITUACAO 1.2",
        "tipoSituacaoId": 1,
        "tipoSituacao": {
            "id": 1,
            "descricao": "TIPO SITUACAO 1"
        }
    },
    {
        "id": 3,
        "descricao": "SITUACAO 2.1",
        "tipoSituacaoId": 2,
        "tipoSituacao": {
            "id": 2,
            "descricao": "TIPO SITUACAO 2"
        }
    }
]

Queries:查询:

Hibernate: select situacao0_.id as id1_0_, situacao0_.descricao as descrica2_0_, situacao0_.tiposituacao_id as tipositu3_0_ from situacao situacao0_
Hibernate: select tiposituac0_.id as id1_1_0_, tiposituac0_.descricao as descrica2_1_0_ from tiposituacao tiposituac0_ where tiposituac0_.id=?
Hibernate: select tiposituac0_.id as id1_1_0_, tiposituac0_.descricao as descrica2_1_0_ from tiposituacao tiposituac0_ where tiposituac0_.id=?

If i use @JsonIgnore , @JsonManageReference or @JsonBackReference o son tipoSituacao until not return , but the query continue executing.如果我使用@JsonIgnore@JsonManageReference@JsonBackReference o son tipoSituacao 直到不返回,但查询会继续执行。

I tried using the DTO, but the same problem.我尝试使用 DTO,但同样的问题。

Every time i use situacaoRepository.find ou findAll the query is executed.每次我使用 situacaoRepository.find 或 findAll 时,都会执行查询。

Project link with problem: https://github.com/maxbrizolla/spring-kotlin-jpa-problem有问题的项目链接: https : //github.com/maxbrizolla/spring-kotlin-jpa-problem

Can someone can help me?有人可以帮助我吗?

The problem here is your data class gets autogenerated toString, equals and hashcode methods which trigger property loading so hibernate execute extra required queries for that.这里的问题是您的数据类会自动生成 toString、equals 和 hashcode 方法,这些方法会触发属性加载,因此 hibernate 会为此执行额外的必需查询。

Data classes are not encouraged to be used with JPA.不鼓励将数据类与 JPA 一起使用。

Because kotlin data class is final so that hibernate cant generate proxy for the lazy fetching entity.因为 kotlin 数据类是最终的,所以 hibernate 无法为延迟获取实体生成代理。 you may fefine TipoSituacao as normal class to make lazy fetching work.你可以把 TipoSituacao 当作普通类来进行懒惰的获取工作。


Sorry about my curtness.抱歉我的鲁莽。 There are some detail I don't mentioned.有一些细节我没有提到。 Talk is cheap and let me show you the code.谈话很便宜,让我向您展示代码。 https://github.com/javaisgood/spring-kotlin-jpa-problem https://github.com/javaisgood/spring-kotlin-jpa-problem

Let's take a look what I have done.让我们来看看我做了什么。

  1. Change data class to normal class and open it as well as its properties.将数据类更改为普通类并打开它及其属性。
@Entity
@Table(name = "TIPOSITUACAO")
open class TipoSituacao(
        @Id
        @Column(name = "ID")
        open val id: Long? = null,

        @Column(name = "DESCRICAO")
        open val descricao: String? = null
)
  1. Add two methods to EndPoints which one doesn't trigger the lazy fetching and another does.向 EndPoints 添加两种方法,一种不会触发延迟获取,另一种会触发。
@RequestMapping("/api")
@RestController
class EndPoints {
    @Autowired
    private val situacaoRepository: SituacaoRepository? = null

    @GetMapping(value = ["/hello"])
    fun hello() = "hello!".also {
        situacaoRepository!!.findAll().forEach {
            println("situacaoId:${it.id}")
            println()
        }
    }

    @GetMapping(value = ["/hello2"])
    fun hello2() = "hello!".also {
        situacaoRepository!!.findAll().forEach {
            println("situacaoId:${it.id}")
            println("tipoSituacaoDescricao:${it.tipoSituacao?.descricao}")
            println()
        }
    }
}

Start the application.启动应用程序。
Call 'hello'.叫“你好”。
Then call 'hello2'.然后调用'hello2'。
The cosole print detail: Cosole印花细节:

Hibernate: select situacao0_.id as id1_0_, situacao0_.descricao as descrica2_0_, situacao0_.tiposituacao_id as tipositu3_0_ from situacao situacao0_
situacaoId:1

situacaoId:2

situacaoId:3

Hibernate: select situacao0_.id as id1_0_, situacao0_.descricao as descrica2_0_, situacao0_.tiposituacao_id as tipositu3_0_ from situacao situacao0_
situacaoId:1
Hibernate: select tiposituac0_.id as id1_1_0_, tiposituac0_.descricao as descrica2_1_0_ from tiposituacao tiposituac0_ where tiposituac0_.id=?
tipoSituacaoDescricao:TIPO SITUACAO 1

situacaoId:2
tipoSituacaoDescricao:TIPO SITUACAO 1

situacaoId:3
Hibernate: select tiposituac0_.id as id1_1_0_, tiposituac0_.descricao as descrica2_1_0_ from tiposituacao tiposituac0_ where tiposituac0_.id=?
tipoSituacaoDescricao:TIPO SITUACAO 2

Now you will see the lazy fetching worked.现在您将看到懒惰的获取工作。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM