[英]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或为空。
FetchType.LAZY
is removed, everything works correctly. FetchType.LAZY
后,一切正常。 open
on the var
so that the Event
can be correctly proxied. var
上添加open
,以便可以正确代理Event
。 No effect. @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.