2011-03-28 133 views
1

我有一個使用Seam和JPA(Hibernate)持久化的對象模型。它看起來是這樣的:Seam/Hibernate/JPA - 重複主鍵異常?

@Entity(name = "MyObject") 
public class MyObject { 

... 

@Id 
@GeneratedValue(strategy = GenerationType.SEQUENCE, generator = "seq_myobj") 
@SequenceGenerator(name = "seq_myobj", sequenceName = "seq_myobj") 
private Long id = null; 

@ManyToOne(cascade = CascadeType.ALL, fetch = FetchType.EAGER, optional = false) 
@NotNull 
    private MySubObject subObjA=null; 

@ManyToOne(cascade = CascadeType.ALL, fetch = FetchType.EAGER, optional = false) 
@NotNull 
    private MySubObject subObjB=null; 

... 

} 

@Entity(name = "MySubObject") 
public class MySubObject { 

... 

@Id 
@GeneratedValue(strategy = GenerationType.SEQUENCE, generator = "seq_mysubobj") 
@SequenceGenerator(name = "seq_mysubobj", sequenceName = "seq_mysubobj") 
private Long id = null; 

} 

我已經正確定義我@ManyToOne註釋和一切。但是,如果我嘗試並堅持MyObject(其中subObjAsubObjB都已設置)的實例,則會發生異常,說明我擁有子對象的重複主鍵之一。什麼會導致這種行爲?兩個對象都將其標識符類型設置爲SEQUENCE,如果我設置了其中一個,則沒有問題。只有當我將兩者都設置爲異常時。

我正在運行Seam 2.2,我的後端數據庫是PostgreSQL。有什麼想法可能會導致這種奇怪的行爲?我認爲這兩個對象都將作爲同一事務的一部分持續存在,並且將自動分配正確的主鍵。就像我說過的,如果我只設置其中一個對象,那麼就沒有問題。它只發生在我把它們都設置好的時候。任何幫助你可以給予很大的讚賞。

編輯但是,我注意到在測試各種事情時出現了一些奇怪的行爲。如果我以編程方式創建MyObject並設置其所有屬性(包括subObj),它仍然沒有問題。但是,如果我使用表單輸入屬性,則會出現錯誤。它可能與交易有關嗎?

+2

您能向我們展示您應用的所有JPA批註嗎? – millhouse 2011-03-29 00:28:10

+0

如果您在MySubObject類中重寫equals/hashCode,請告訴我們。 – 2011-03-29 11:16:45

+0

編輯包含subObjA/B屬性的註釋 – Shadowman 2011-03-29 17:18:20

回答

0

通過一系列的測試和不同的場景,並發現它的工作場合。所以,當我提交併保存到數據庫時,看起來我的操作類中存在一個錯誤。

0

如果覆蓋MySubObject類中的equals/hashCode,請確保這些方法只檢查代理鍵id(在這種情況下,您應該完全避免它們)。

如果equals/hashCode方法適用於某些業務密鑰屬性,請確保這些密鑰在持續之前是唯一的。

+0

我試過了,但仍然收到同樣的錯誤。但是,我注意到在測試各種事物時出現了一些奇怪的行爲。如果我以編程方式創建MyObject並設置其所有屬性(包括subObj),它仍然沒有問題。但是,如果我使用表單輸入屬性,則會出現錯誤。它可能與交易有關嗎? – Shadowman 2011-03-31 00:58:39

+0

如果表單的行爲如此,它可能需要處理事務:第一個subObj獲得持久性,失敗事務中序列中的ID。隨後的異常被屏蔽並且代碼繼續保留第二個subObj,以便它獲得相同的ID。 – 2011-03-31 07:25:45

+0

表單是兩步數據提交過程的一部分。在第一頁上,用戶輸入他們提交的數據的一些基本信息。在第二頁上,他們輸入更詳細的信息,包括設置subObjA和subObjB的屬性。在用戶單擊第二頁上的「提交」之前,不會進行entityManager.update()調用。這就是我看到異常的地方,所以現在我認爲它與這個工作流相關,因爲我可以通過編程方式創建對象而沒有任何問題。任何想法發生了什麼?我應該嘗試的事情? – Shadowman 2011-03-31 12:56:34