2009-12-19 25 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