0

I have a project in Java and i am converting to Kotlin, but the entities with relations and mapping @ManytoOne they are with problems. The entities they are using mapping fecht type LAZY, aren't they respecting the LAZY and executing the query.

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.

I tried using the DTO, but the same problem.

Every time i use situacaoRepository.find ou findAll the query is executed.

Project link with problem: https://github.com/maxbrizolla/spring-kotlin-jpa-problem

Can someone can help me?

  • I think my problem was similar: https://stackoverflow.com/questions/53816797/kotlin-hibernate-jpa-lazy-fetch-not-working-through-the-controller – Márton Osváth Dec 18 '18 at 09:12

2 Answers2

0

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.

Data classes are not encouraged to be used with JPA.

Juan Rada
  • 3,513
  • 1
  • 26
  • 26
-1

Because kotlin data class is final so that hibernate cant generate proxy for the lazy fetching entity. you may fefine TipoSituacao as normal class to make lazy fetching work.


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

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.
@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'.
The cosole print detail:

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.

Jango
  • 640
  • 1
  • 5
  • 14