使用Kotlin休眠:@ManyToOne(fetch = FetchType.LAZY) [英] Hibernate with Kotlin: @ManyToOne(fetch = FetchType.LAZY)

查看:79
本文介绍了使用Kotlin休眠:@ManyToOne(fetch = FetchType.LAZY)的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我正在将Kotlin与Hibernate一起使用,并且在@ManyToOne关系上遇到了FetchType.LAZY的问题.考虑以下内容:

I am using Hibernate with Kotlin and I am having an issue with FetchType.LAZY on @ManyToOne relations. Consider following:

@ManyToOne(fetch = FetchType.LAZY)
open var event: Event?

问题是,当使用FetchType.LAZY时,获取的Event将属于带有JavaassistLazyInitializerEvent_$$_jvst_...类.但是该事件永远不会初始化,所有内容都将为null或为空.

The problem is that when FetchType.LAZY is used, the fetched Event will be of class Event_$$_jvst_... with JavaassistLazyInitializer on it. But the event will never be initialized, everything will be null or empty.

  1. 一旦FetchType.LAZY被删除,一切正常.
  2. 这不是在Java中发生的.
  3. 我试图在var上添加open,以便可以正确地代理Event.没有效果.
  4. 所有@Entity类当然也是open.如果删除open关键字,将不会创建任何代理,因此不会造成任何延迟.
  1. Once the FetchType.LAZY is removed, everything works correctly.
  2. This didn't happen in Java.
  3. I tried to add open on the var so that the Event can be correctly proxied. No effect.
  4. All the @Entity classes are of course open as well. If the open keyword is removed, there will be no proxy created and so no laziness.

我的猜测是Hibernate无法轻易代理这些默认的Kotlin getter.有办法解决吗?

My guess is that Hibernate cannot easily proxy these default kotlin getters. Is there a way to solve it?

推荐答案

我写了一个简单的示例来检查您的问题,并且一切正常.

I write a simple example to check your problem, and all works fine.

import org.hibernate.CacheMode
import org.hibernate.Session
import org.hibernate.SessionFactory
import org.hibernate.Transaction
import org.hibernate.boot.MetadataSources
import org.hibernate.boot.registry.StandardServiceRegistryBuilder
import org.hibernate.cfg.Environment
import java.util.*
import javax.persistence.*


fun main(args: Array<String>) {
    val standardServiceRegistryBuilder = StandardServiceRegistryBuilder()

    val settings = HashMap<String, String>().apply {
        put(Environment.DRIVER, "org.h2.Driver")
        put(Environment.URL, "jdbc:h2:mem:myDb;DB_CLOSE_DELAY=-1")
        put(Environment.USER, "sa")
        put(Environment.PASS, "sa")
        put(Environment.DIALECT, "org.hibernate.dialect.H2Dialect")
        put(Environment.SHOW_SQL, "true")
        put(Environment.HBM2DDL_AUTO, "create")
    }

    val sessionFactory = standardServiceRegistryBuilder.applySettings(settings)
            .build()
            .let {
                MetadataSources(it).apply {
                    addAnnotatedClass(History::class.java)
                    addAnnotatedClass(Event::class.java)
                }
            }
            .run { metadataBuilder.build() }
            .run { sessionFactoryBuilder.build() }

    sessionFactory.inSession {
        inTransaction { session ->
            session.save(Event(1, "event description"))

            session.save(History(1, Event(1), "history description"))
        }
    }

    sessionFactory.inSession {
        inTransaction { session ->
            val entity = session.get(Event::class.java, 1L)

            println("=============1=============")
            println(entity)
        }
    }

    sessionFactory.inSession {
        inTransaction { session ->
            val entity = session.load(History::class.java, 1L)

            println("=============2=============")
            println(entity)
        }
    }
}

private fun SessionFactory.inSession(function: Session.() -> Unit) {
    val session = this.openSession()

    session.function()

    session.close()
}

private fun Session.inTransaction(function: Transaction.(s: Session) -> Unit) {
    val transaction = this.beginTransaction()

    transaction.function(this)

    transaction.commit()
}

@Entity
open class History(
        @Id
        open var id: Long? = null,

        @ManyToOne(fetch = FetchType.LAZY)
        @JoinColumn(name = "eventId")
        open var event: Event? = null,

        open var description: String = ""
) {
    override fun toString(): String {
        return "History(id=$id, event=$event, description='$description')"
    }
}

@Entity
open class Event(
        @Id
        open var id: Long? = null,
        open var description: String? = null,

        @OneToMany(fetch = FetchType.LAZY, mappedBy = "event")
        open var history: MutableSet<History>? = null
) {
    override fun toString(): String {
        return "Event(id=$id, description='$description', history=${history?.size})"
    }
}

日志如下:

2017-12-05 18:43:03 [main] INFO  org.hibernate.Version - HHH000412: Hibernate Core {5.2.12.Final}
2017-12-05 18:43:03 [main] INFO  org.hibernate.cfg.Environment - HHH000206: hibernate.properties not found
2017-12-05 18:43:03 [main] INFO  o.h.annotations.common.Version - HCANN000001: Hibernate Commons Annotations {5.0.1.Final}
2017-12-05 18:43:04 [main] WARN  o.hibernate.orm.connections.pooling - HHH10001002: Using Hibernate built-in connection pool (not for production use!)
2017-12-05 18:43:04 [main] INFO  o.hibernate.orm.connections.pooling - HHH10001005: using driver [org.h2.Driver] at URL [jdbc:h2:mem:myDb;DB_CLOSE_DELAY=-1]
2017-12-05 18:43:04 [main] INFO  o.hibernate.orm.connections.pooling - HHH10001001: Connection properties: {password=****, user=sa}
2017-12-05 18:43:04 [main] INFO  o.hibernate.orm.connections.pooling - HHH10001003: Autocommit mode: false
2017-12-05 18:43:04 [main] INFO  o.h.e.j.c.i.DriverManagerConnectionProviderImpl - HHH000115: Hibernate connection pool size: 20 (min=1)
2017-12-05 18:43:04 [main] INFO  org.hibernate.dialect.Dialect - HHH000400: Using dialect: org.hibernate.dialect.H2Dialect
2017-12-05 18:43:04 [main] INFO  o.h.validator.internal.util.Version - HV000001: Hibernate Validator 5.3.5.Final
WARNING: An illegal reflective access operation has occurred
WARNING: Illegal reflective access by javassist.util.proxy.SecurityActions (file:/Users/evgenyzaharov/.gradle/caches/modules-2/files-2.1/org.javassist/javassist/3.20.0-GA/a9cbcdfb7e9f86fbc74d3afae65f2248bfbf82a0/javassist-3.20.0-GA.jar) to method java.lang.ClassLoader.defineClass(java.lang.String,byte[],int,int,java.security.ProtectionDomain)
WARNING: Please consider reporting this to the maintainers of javassist.util.proxy.SecurityActions
WARNING: Use --illegal-access=warn to enable warnings of further illegal reflective access operations
WARNING: All illegal access operations will be denied in a future release
Hibernate: drop table Event if exists
2017-12-05 18:43:04 [main] INFO  org.hibernate.orm.connections.access - HHH10001501: Connection obtained from JdbcConnectionAccess [org.hibernate.engine.jdbc.env.internal.JdbcEnvironmentInitiator$ConnectionProviderJdbcConnectionAccess@56913163] for (non-JTA) DDL execution was not in auto-commit mode; the Connection 'local transaction' will be committed and the Connection will be set into auto-commit mode.
Hibernate: drop table History if exists
Hibernate: create table Event (id bigint not null, description varchar(255), primary key (id))
2017-12-05 18:43:04 [main] INFO  org.hibernate.orm.connections.access - HHH10001501: Connection obtained from JdbcConnectionAccess [org.hibernate.engine.jdbc.env.internal.JdbcEnvironmentInitiator$ConnectionProviderJdbcConnectionAccess@e8e0dec] for (non-JTA) DDL execution was not in auto-commit mode; the Connection 'local transaction' will be committed and the Connection will be set into auto-commit mode.
Hibernate: create table History (id bigint not null, description varchar(255), eventId bigint, primary key (id))
Hibernate: alter table History add constraint FK2yaqfgh2x1lsxcpbuifmd245k foreign key (eventId) references Event
2017-12-05 18:43:04 [main] INFO  o.h.t.s.internal.SchemaCreatorImpl - HHH000476: Executing import script 'org.hibernate.tool.schema.internal.exec.ScriptSourceInputNonExistentImpl@6c15e8c7'
Hibernate: select event_.id, event_.description as descript2_0_ from Event event_ where event_.id=?
Hibernate: insert into Event (description, id) values (?, ?)
Hibernate: insert into History (description, eventId, id) values (?, ?, ?)
Hibernate: update History set description=?, eventId=? where id=?
Hibernate: select event0_.id as id1_0_0_, event0_.description as descript2_0_0_ from Event event0_ where event0_.id=?
=============1=============
Hibernate: select history0_.eventId as eventId3_1_0_, history0_.id as id1_1_0_, history0_.id as id1_1_1_, history0_.description as descript2_1_1_, history0_.eventId as eventId3_1_1_ from History history0_ where history0_.eventId=?
Event(id=1, description='event description', history=1)
=============2=============
Hibernate: select history0_.id as id1_1_0_, history0_.description as descript2_1_0_, history0_.eventId as eventId3_1_0_ from History history0_ where history0_.id=?
Hibernate: select event0_.id as id1_0_0_, event0_.description as descript2_0_0_ from Event event0_ where event0_.id=?
Hibernate: select history0_.eventId as eventId3_1_0_, history0_.id as id1_1_0_, history0_.id as id1_1_1_, history0_.description as descript2_1_1_, history0_.eventId as eventId3_1_1_ from History history0_ where history0_.eventId=?
History(id=1, event=Event(id=1, description='event description', history=1), description='history description')

Lazy初始化仅在显式获取值之后才开始加载字段数据.

Lazy initialisation start to load field data only after explicit getting a value.

希望这会对您有所帮助.

Hope this will help you.

这篇关于使用Kotlin休眠:@ManyToOne(fetch = FetchType.LAZY)的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆