2009-12-19 75 views
1

我有一個JPA項目連接到一個MySQL數據庫,其中我的實體對象映射到一個約束2列的表。即:堅持一個新的但相同的實體與JPA報告重複條目

@Entity 
@Table(name = "my_entity") 
class MyEntity { 
    @Id 
    @GeneratedValue(strategy = GenerationType.IDENTITY) 
    @Basic(optional = false) 
    @Column(name = "id") 
    private Integer id; 
    @Basic(optional = false) 
    @Column(name = "myField1") 
    private String myField1; 
    @Basic(optional = false) 
    @Column(name = "myField2") 
    private int myField2; 
    @OneToMany(cascade = CascadeType.ALL, mappedBy = "myEntity") 
    private Set<OtherEntity> otherEntitySet; 
} 

在數據庫中,my_entity表對(myField1,myField2)具有唯一約束。問題是,如果我使用EntityManager.remove(entity)刪除現有實體,然後使用EntityManager.persist(entity)添加新實體,數據庫將拋出關於重複行的錯誤。

例如:

entityManager.getTransaction().begin(); 

MyEntity entity1 = new MyEntity(); 
entity1.setMyField1("Foo"); 
entity1.setMyField2(500); 
entityManager.persist(entity1); 

entityManager.getTransaction().commit(); 
entityManager.getTransaction().begin(); 

entityManager.remove(entity1); 

MyEntity entity2 = new MyEntity(); 
entity2.setMyField1("Foo"); 
entity2.setMyField2(500); 
entityManager.persist(entity2); 

entityManager.getTransaction().commit(); 

這給了我MySQLIntegrityConstraintViolationException抱怨這是一個重複的條目。我想這是因爲它試圖在刪除舊條目之前添加新條目。有什麼辦法維持這個訂單嗎?或者,有沒有辦法使用JPA來防止這種情況?這不是一個常見的用例,但我擔心試圖刪除實體以刪除所有關聯數據並重新開始的用戶,然後重新創建更簡單的字段,然後發現數據從未被刪除。

將hashCode和等於實現如下:

public int hashCode() { 
    int hash = 0; 
    hash += (getMyField1().hashCode() + getMyField2()); 
    return hash; 
} 

public boolean equals(Object object) { 
    if (!(object instanceof MyEntity)) { 
     return false; 
    } 
    MyEntity other = (MyEntity) other; 
    return (getMyField2() == other.getMyField2()) && 
     (getMyField1().equals(other.getMyField1())); 
} 
+0

您可以加入您的equals和hashCode實現? – 2009-12-19 08:55:34

+0

加入 - 我最初有一個等於檢查Id的快捷方式,但我刪除它來確認。同樣的問題。 – Jon 2009-12-19 15:17:40

回答

2

我不認爲這是指定在JPA操作順序任何標準的方式,所以也不能保證該命令語句將被執行。理想情況下,JPA實現足夠聰明以檢測這種情況並在插入之前執行刪除,但這是他們經常失敗的區域。或者,如果您的數據庫支持延遲約束檢查(例如,Oracle可以,但MySQL不會),數據庫將通過等待提交時間來處理這個事件,以提供唯一的違反約束的異常。

因此,一種解決方案是在您調用remove(entity1)之後執行額外的提交。另一種可能性是,在創建entity2之前,首先檢查它是否存在於數據庫中,如果存在,就使用那個。這兩個選項都可能有點麻煩,不適合所有工作流程。您可能需要深入瞭解當前JPA實現的文檔,以確定它們是否提供了可能有所幫助的擴展。

+0

這絕對是指向正確的方向。我現在看到對JPA的引用(我特別使用EclipseLink)在刪除之前默認進行插入操作。應用程序允許用戶在任何時候保存或取消,所以我不能在刪除後進行提交,但我正在考慮更改重用功能中的默認或構建。 – Jon 2009-12-19 19:36:21

+0

我懷疑你想說:remove(entity1)之後顯式的'flush()'。沒有必要提交,這是一個壞主意(最好把整個方法放在一個TRA中) – pihentagy 2010-07-26 16:24:25

0

我有同樣的問題涉及UC和插入/刪除發生在錯誤的順序。我必須爲我的實體創建一個與UC列相匹配的組合鍵。之後,刪除和插入以正確的順序進行。看到這個帖子,以及關於添加@EmbeddedId評論:

https://forum.hibernate.org/viewtopic.php?p=2382504

+0

我認爲我有一個總體思路,但是我對這些細節有點遺憾。你能舉一個簡單的例子嗎? 說,如果我有一個簡單的聯繫人信息表,該怎麼辦。我在數據庫中有一個唯一的約束(id int,name varchar),其他錶鏈接到該id。 我正在編輯我的地址簿,然後轉到「哦,我不是Eddie的朋友了」,因此我刪除了該條目,並將其級聯到任何其他關聯數據。但是在更新其他人(而不是保存)之後,我完全輸入「Eddie」作爲其他人的條目。根據我設計的JPA,會引發錯誤。 – Jon 2010-01-29 17:01:28

相關問題