Java 与Kotlin一起休眠:@ManyToOne(fetch=FetchType.LAZY)

Java 与Kotlin一起休眠:@ManyToOne(fetch=FetchType.LAZY),java,hibernate,kotlin,Java,Hibernate,Kotlin,我正在将Hibernate与Kotlin一起使用,我在@manytone关系上遇到了FetchType.LAZY问题。考虑如下: @ManyToOne(fetch = FetchType.LAZY) open var event: Event? 问题是,当使用FetchType.LAZY时,获取的事件将属于类Event\u$$\ uvst\u……,其上带有JavaassistLazyInitializer。但事件永远不会被初始化,所有内容都将为null或空 删除FetchType.LAZY后,

我正在将Hibernate与Kotlin一起使用,我在
@manytone
关系上遇到了
FetchType.LAZY
问题。考虑如下:

@ManyToOne(fetch = FetchType.LAZY)
open var event: Event?
问题是,当使用
FetchType.LAZY
时,获取的
事件
将属于类
Event\u$$\ uvst\u……
,其上带有
JavaassistLazyInitializer
。但事件永远不会被初始化,所有内容都将为null或空

  • 删除
    FetchType.LAZY
    后,一切正常
  • 这在Java中没有发生
  • 我试图在
    var
    上添加
    open
    ,以便可以正确代理
    事件。没有效果
  • 所有的
    @实体
    类当然也都是
    打开的
    。如果删除
    open
    关键字,则不会创建代理,因此不会出现惰性

  • 我猜Hibernate不能轻易地代理这些默认的kotlin getter。有办法解决吗?

    您可以使用此静态方法来解除实体的代理

    /**
     * Utility method that tries to properly initialize the Hibernate CGLIB
     * proxy.
     * @param <T>
     * @param maybeProxy -- the possible Hibernate generated proxy
     * @param baseClass -- the resulting class to be cast to.
     * @return the object of a class <T>
     * @throws ClassCastException
     */
    public static <T> T deproxy(Object maybeProxy, Class<T> baseClass) throws ClassCastException {
        if (maybeProxy instanceof HibernateProxy) {
            return baseClass.cast(((HibernateProxy) maybeProxy).getHibernateLazyInitializer().getImplementation());
        }
        return baseClass.cast(maybeProxy);
    }
    
    /**
    *尝试正确初始化Hibernate CGLIB的实用程序方法
    *代理。
    *@param
    *@param maybeProxy——可能由Hibernate生成的代理
    *@param baseClass--要强制转换到的结果类。
    *@返回类的对象
    *@ClassCastException
    */
    公共静态T deproxy(对象可能是代理,类基类)抛出ClassCastException{
    if(可能是HibernateProxy的代理实例){
    返回baseClass.cast(((HibernateProxy)maybeProxy).getHibernateLazyInitializer().getImplementation());
    }
    返回baseClass.cast(maybeProxy);
    }
    
    我写了一个简单的例子来检查您的问题,一切正常

    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})"
        }
    }
    
    Lazy
    初始化仅在显式获取值后才开始加载字段数据

    希望这对你有帮助

    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')