gpt4 book ai didi

java - JPA。如何子类化现有实体并保留其 ID?

转载 作者:塔克拉玛干 更新时间:2023-11-03 02:57:23 25 4
gpt4 key购买 nike

假设我有两个经典的非抽象 JPA 类:Person 和 Student。

@Entity
@Inheritance(strategy = InheritanceType.JOINED)
public class Person {
@Id
@GeneratedValue(strategy = GenerationType.AUTO)
private String id;
// ...
}

@Entity
public class Student extends Person {
// ...
}

现在有一些身份的人进入大学并成为一名学生。我如何在 JPA 中处理该事实并保留人员的 ID?

student = new Student();
student.setPersonData(person.getPersonData());
student.setId(person.getId());
entityManager.persist(student);

上面的代码产生“分离的实体传递给持久化”异常,而使用 entityManager.merge(student) 跳过分配的 id 并创建两个新实体 Person 和 Student新身份证。有什么想法可以保留原始 ID 吗?

最佳答案

JPA 规范禁止应用程序更改实体的标识(第 2.4 节):

The application must not change the value of the primary key[10]. The behavior is undefined if this occurs.[11]

此外,在使用连接继承策略执行跨实体继承的表的情况下,标识仅在根类中定义。所有子类只存储类的局部属性。

通过调用 student.setId(person.getId());您正在尝试将尚未保留的实体的身份更改为现有实体的身份。这本身没有意义,特别是因为您正在使用 AUTO 的序列生成策略(通常是 TABLE)为身份生成值。

如果我们忽略前面的几点,并且如果您希望将 Person 转换为 Student 而不丢失身份,那么这或多或少是不可能的(至少以干净的方式,正如@axtavt 指出的那样).原因很简单,您无法在运行时成功地将 Person 向下转换为 Student,因为这是您在现实生活中尝试执行的自然的面向对象操作。即使你以假设的方式向下转型成功,原始实体也有一个鉴别器列值需要修改;在不知道 JPA 提供程序如何使用和缓存此值的情况下,任何使用 native SQL 更改数据的尝试都可能导致比其值(value)更多的麻烦。

如果您不反对丢失生成的 ID(毕竟人们通常会生成它们,这样您就可以使用自然键或者您不必公开共享这些生成的 ID),您应该创建一份Person 对象并将其重新创建为 Student。这将确保 JPA 提供程序也将正确填充鉴别器列。此外,您还需要删除原始的 Person 实体。

以上所有内容,都考虑到您不会修改当前的对象模型。如果您可以修改对象模型,您就有机会保留原始 ID。这将要求您放弃继承层次结构,因为它首先自然不适合您的领域。从 Person 向下转换为 Student 的尝试表明继承不是天作之合。遵循 @axtavt 的建议更合适,因为如果您仔细阅读它(至少我是这样读的),它实际上意味着支持组合而不是继承。

JPA Wikibook 在关于 Object Reincarnation 的部分讨论了这种情况。 。请注意关于拥有 type 的具体建议实体中的属性,而不是使用继承来更改对象的类型。

Reincarnation

Normally an object that has been removed, stays removed, but in some cases you may need to bring the object back to life. This normally occurs with natural ids, not generated ones, where a new object would always get an new id. Generally the desire to reincarnate an object occurs from a bad object model design, normally the desire to change the class type of an object (which cannot be done in Java, so a new object must be created). Normally the best solution is to change your object model to have your object hold a type object which defines its type, instead of using inheritance. But sometimes reincarnation is desirable.

关于java - JPA。如何子类化现有实体并保留其 ID?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/6421412/

25 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com