我正在尝试使用 Kotlin 和 JPA 实现继承。我的抽象基类(用 @Entity
注释)保存 ID(用 @Id
和 @GenerateValue
注释)和其他元数据,如 createDate、我从 Hibernate 收到几个错误,除了 ID 之外的每个字段都有一个错误:
org.hibernate.tuple.entity.PojoEntityTuplizer - HHH000112: Getters of lazy classes cannot be final: com.example.BaseEntity.createDate
正如我所读,我需要为每个属性包含 open 关键字。
我对此有 3 个问题:
- 为什么我必须在父类(super class)中这样做,而在子类中不需要?我不会覆盖这些属性。
- 为什么它不提示 ID?
- 似乎没有 open 关键字就可以工作,那么为什么会记录错误?
编辑:
@Entity
@Inheritance(strategy = InheritanceType.JOINED)
abstract class BaseEntity(
@Id @GeneratedValue(strategy = GenerationType.IDENTITY) val id: Long = 0,
val createdAt: Instant = Instant.now()
)
@Entity
class SubClass(
val someProperty: String = ""
) : BaseEntity()
我正在使用 Gradle 的 JPA 插件,我相信它会创建 noarg 构造函数,这就是为什么我不必指定所有可为 null 的内容。
谢谢!
最佳答案
记录的错误与lazy loading有关。 .
Hibernate 在运行时扩展
实体以启用它。这是通过在延迟加载实体时拦截对属性的访问来完成的。
Kotlin 颠覆了规则,默认情况下所有类都是 final
。这就是为什么我们建议添加 open
关键字的原因。
如果属性不是open
,hibernate 无法拦截对其的访问,因为final
方法无法被覆盖。因此出现错误。
Why isn't it complaining about the ID?
因为 @Id
始终加载。无需拦截对其的访问。
It seems to work without the
open
keyword, then why is the error logged?
这里的关键词是似乎。它可能会引入微妙的错误。
考虑以下@Entity
:
@Entity
public class Book {
@Id
private Long id;
private String title;
public final Long getId() {
return id;
}
public void setId(Long id) {
this.id = id;
}
public final String getTitle() {
return title;
}
public void setTitle(String title) {
this.title = title;
}
}
还有@Test
:
@Test
public void test() {
EntityManager entityManager = entityManagerFactory.createEntityManager();
entityManager.getTransaction().begin();
// signal here
Book book = new Book();
book.setId(1L);
book.setTitle("myTitle");
entityManager.persist(book);
// noise
entityManager.getTransaction().commit();
entityManager.close();
entityManager = entityManagerFactory.createEntityManager();
entityManager.getTransaction().begin();
// signal
Book reference = entityManager.getReference(Book.class, 1L);
String title = reference.getTitle();
assertNull(title); // passes
entityManager.getTransaction().commit();
entityManager.close();
}
此测试通过,但不应通过(如果getTitle
不是final
,则失败)。
这很难被注意到
Why do I have to do that in the superclass, and don't need in subclass? I'm not overriding those properties.
看起来 Hibernate 在看到 final
@Entity
时放弃了。
将open
添加到SubClass
中,您将获得宝贵的:
2019-05-02 23:27:27.500 ERROR 5609 --- [ main] o.h.tuple.entity.PojoEntityTuplizer : HHH000112: Getters of lazy classes cannot be final: com.caco3.hibernateanswer.SubClass.someProperty
另请参阅:
- final methods on entity silently breaks lazy proxy loading
- How to avoid initializing HibernateProxy when invoking toString() on it? - 我的旧问题(请注意,Hibernate 最近使用 Byte Buddy)。
PS
您是否忘记在 BaseEntity
上包含 @MappedSuperclass
?
如果没有注释,它应该会失败,并显示如下内容:
org.hibernate.AnnotationException: No identifier specified for entity: com.caco3.hibernateanswer.SubClass
关于jpa - Kotlin 继承和 JPA,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/55958667/