簡體   English   中英

JPA。如何將現有實體子類化並保留其ID?

[英]JPA. How do I subclass existing entity and keep its ID?

假設我有兩個經典的非抽象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中處理這個事實並保持個人身份?

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

上面的代碼生成'傳遞給持久化的分離實體'異常,而使用entityManager.merge(student)跳過分配的id並創建具有新id的Person和Student的兩個新實體。 任何想法如何保持原始ID?

JPA規范禁止應用程序更改實體的身份(第2.4節):

應用程序不得更改主鍵的值[10]。 如果發生這種情況,行為是不確定的。[11]

此外,對於使用連接的繼承策略執行跨實體的繼承的表,僅在根類中定義標識。 所有子類僅存儲類的本地屬性。

通過調用student.setId(person.getId()); 您試圖將尚未持久化的實體的身份更改為現有實體的身份。 這本身沒有意義,特別是因為您使用AUTO的序列生成策略(通常是TABLE)為身份生成值。

如果我們忽略了之前的觀點,並且如果你希望將Person轉換為Student,而不會丟失身份,那么這或多或少是不可能的(至少以干凈的方式,正如@axtavt指出的那樣)。 原因很簡單,您無法在運行時成功地從Person向學生轉發,因為這是您嘗試在現實生活中執行的自然面向對象操作。 即使您以假設的方式成功進行了預測,原始實體也有一個需要修改的鑒別器列值; 在不知道JPA提供程序如何使用和緩存此值的情況下,使用本機SQL進行數據更改的任何嘗試都可能導致比實際值更多的麻煩。

如果您不想丟失生成的ID(畢竟通常會生成它們,以便您可以使用自然鍵,或者您不必公開共享這些生成的ID),您應該創建Person對象的副本,將其重新創建為學生。 這將確保JPA提供程序也將正確填充鑒別器列。 此外,您還需要刪除原始的Person實體。

以上所有,都在考慮您不會修改當前的對象模型。 如果您可以修改對象模型,則可能會保留原始ID。 這將要求您刪除繼承層次結構,因為它首先不適合您的域。 從一個人向學生傾斜的嘗試表明繼承不是一個自然的契合。 遵循@ axtavt的建議更合適,因為它實際上意味着有利於組合而不是繼承,如果你仔細閱讀(至少我是這樣讀的)。

JPA Wikibook在Object Reincarnation一節中討論了這種情況。 請注意有關在實體中使用type屬性而不是使用繼承來更改對象類型的具體建議。

投胎

通常情況下,已移除的對象會被移除,但在某些情況下,您可能需要將對象恢復生命。 這通常發生在自然的id中,而不是生成的id,其中新的對象總是會獲得新的id。 通常,重新生成對象的願望來自不良對象模型設計,通常是改變對象的類類型的願望(不能用Java完成,因此必須創建新對象)。 通常,最好的解決方案是更改對象模型,讓對象保存一個定義其類型的類型對象,而不是使用繼承。 但有時輪回是可取的。

據我所知,沒有好辦法實現它。

如果你對此建模一發而動這將是更simplier Person可以擁有多個角色Role S(一個一對多的關系),其中Student是其中之一(即Student伸出Role )。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM