简体   繁体   English

使用Kotlin进行Hibernate:@ManyToOne(fetch = FetchType.LAZY)

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

I am using Hibernate with Kotlin and I am having an issue with FetchType.LAZY on @ManyToOne relations. 我使用Hibernate与科特林和我有一个问题FetchType.LAZY@ManyToOne关系。 Consider following: 考虑以下:

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

The problem is that when FetchType.LAZY is used, the fetched Event will be of class Event_$$_jvst_... with JavaassistLazyInitializer on it. 问题是当使用FetchType.LAZY时,获取的Event将是类Event_$$_jvst_...并且带有JavaassistLazyInitializer But the event will never be initialized, everything will be null or empty. 但事件永远不会被初始化,一切都将为null或为空。

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

My guess is that Hibernate cannot easily proxy these default kotlin getters. 我的猜测是Hibernate无法轻易代理这些默认的kotlin getter。 Is there a way to solve it? 有办法解决吗?

you could use this static method to deproxy your entity 您可以使用此静态方法来对您的实体进行deproxy

/**
 * 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);
}

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})"
    }
}

Logs looks like this: 日志看起来像这样:

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 initialisation start to load field data only after explicit getting a value. Lazy初始化仅在显式获取值后才开始加载字段数据。

Hope this will help you. 希望这会帮助你。

暂无
暂无

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

相关问题 休眠@MappedSuperclass @ManyToOne(fetch = FetchType.LAZY) - Hibernate @MappedSuperclass @ManyToOne(fetch=FetchType.LAZY) Hibernate @ManyToOne(fetch = FetchType.LAZY)被忽略 - Hibernate @ManyToOne(fetch = FetchType.LAZY) ignored Hibernate ManyToOne FetchType.LAZY无法正常工作? - Hibernate ManyToOne FetchType.LAZY is not working? FetchType.LAZY在休眠中不适用于@ManyToOne映射 - FetchType.LAZY not working for @ManyToOne mapping in hibernate Hibernate @OneToOne(fetch = FetchType.LAZY)无效 - Hibernate @OneToOne(fetch = FetchType.LAZY) is not working 尽管已设置FetchType.Lazy,但Hibernate / Jpa还是急切地获取@ManyToOne对象。 - Hibernate/Jpa fetch eagerly @ManyToOne object although FetchType.Lazy is setted 休眠:@ManyToOne(fetch = FetchType.LAZY) 对非主键引用列不起作用 - Hibernate: @ManyToOne(fetch = FetchType.LAZY) does not work on non-primary key referenced column 为什么Hibernate(JPA)对于ManyToOne关系忽略FetchType.LAZY? - Why does Hibernate (JPA) ignore FetchType.LAZY for ManyToOne relations? @ManyToOne(fetch=FetchType.LAZY, optional=false) 仍在获取 - @ManyToOne(fetch=FetchType.LAZY, optional=false) still fetching Spring Data JPA,Hibernate,@ ManyToOne(fetch = FetchType.LAZY)和org.hibernate.LazyInitializationException:无法初始化代理-没有会话 - Spring Data JPA, Hibernate, @ManyToOne(fetch=FetchType.LAZY) and org.hibernate.LazyInitializationException: could not initialize proxy - no Session
 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM