Спящий режим с Kotlin: @ManyToOne (fetch = FetchType.LAZY)

Я использую Hibernate с Kotlin, и у меня возникает проблема с FetchType.LAZY в отношениях @ManyToOne . Рассмотрим следующее:

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

Проблема в том, что когда используется FetchType.LAZY Event будет состоять из класса Event_$$_jvst_... с JavaassistLazyInitializer . Но событие никогда не будет инициализировано, все будет пустым или пустым.

  1. После FetchType.LAZY все работает правильно.
  2. Это не произошло на Java.
  3. Я попытался добавить open на var чтобы Event могло быть правильно проксировано. Нет эффекта.
  4. Все классы @Entity , конечно же, open . Если ключевое слово open будет удалено, не будет создан прокси-сервер и поэтому не будет лень.

Я предполагаю, что Hibernate не может легко проксировать эти по умолчанию kotlin getters. Есть ли способ решить эту проблему?

вы можете использовать этот статический метод для депроксирования своей сущности

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

Я пишу простой пример, чтобы проверить вашу проблему, и все работает нормально.

 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 ohannotations.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 ohejciDriverManagerConnectionProviderImpl - 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 ohvalidator.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 ohtsinternal.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 инициализация начинает загружать данные поля только после явного получения значения.

Надеюсь, что это поможет вам.

Intereting Posts
Kotlin: Сравнить значения свойств различных целевых объектов с (out) отражением kotlin, используя тип генериков класса данных Как я могу подавить непроверенные предупреждения о броске? Отсутствует функция Kotlin View setEnabled? RXJava … излучает наблюдаемую каждую секунду Генериры Котлина Массив <T> приводит к «Невозможно использовать T как параметр типа reified. Вместо этого используйте класс, но List <T> не делает Выравнивание с котлин и маслобойник Android SpeechRecognizer не запускается снова Sugar ORM, Список всех в Котлин? Java работает, но Kotlin не Повторная установка 2, Rx 2 и асинхронные вызовы Как я могу ссылаться на неназванный аргумент выражения when? eclipse организует импорт, не работающий с файлами kotlin Почему Котлин не следил за синтаксисом Java? Использование функции Kotlin как типа Java SAM В Котлине, как сделать свойство доступным только для определенного типа