jpa - Kotlin 继承和 JPA

标签 jpa inheritance kotlin spring-data-jpa

我正在尝试使用 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 个问题:

  1. 为什么我必须在父类(super class)中这样做,而在子类中不需要?我不会覆盖这些属性。
  2. 为什么它不提示 ID?
  3. 似乎没有 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 

另请参阅:

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/

相关文章:

android - 如何使用 Moshi 解析对对象模型的改造 json 响应

java - 在 Android 的 MVP 设计模式中,我们在哪里放置业务登录?

java - 配置 Liberty Profile 以使用 H2 数据库

java - 如何在 JPA 中使用额外的 where 子句限制 ManyToMany

c++ - arduino c++ 中的继承问题

c++ - 如何知道ID2D1Brush是哪种画笔?

java - Kotlin-无法推断泛型

java - Spring Data JPARepository 和@Transactional 用于一个方法内的多个操作

spring - 无法构建 ClassFile - ArchiveException

C++ 继承和赋值运算符