使用 JPA 报告重复条目来保留新的但相同的实体

发布于 2024-08-14 21:47:53 字数 1843 浏览 4 评论 0原文

我有一个连接到 MySQL 数据库的 JPA 项目,其中我的实体对象映射到一个具有 2 列约束的表。即:

@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和equals的实现如下:

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()));
}

I have a JPA project connected to a MySQL database where my entity object is mapped to a table with a constraint on 2 columns. That is:

@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;
}

In the database, the my_entity table has a unique constraint on (myField1, myField2). The issue is that if I remove an existing entity with EntityManager.remove(entity) and then add a new one with EntityManager.persist(entity), the database throws an error about a duplicate row.

For example:

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();

This gives me a MySQLIntegrityConstraintViolationException complaining about this being a duplicate entry. I imagine it's because it's trying to add the new entry before removing the old one. Is there any way to maintain that order? Or, is there a way to use JPA to prevent this situation? It's not exactly a common use case, but I'm concerned about a user who tries to delete an entity to get rid of all the associated data and start over, and then recreates the easier fields, then finding that the data was never removed.

The hashCode and equals implementations are as follows:

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()));
}

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(2

沫雨熙 2024-08-21 21:47:53

我认为 JPA 中没有任何标准方法来指定操作顺序,因此无法保证语句将执行的顺序。理想情况下,JPA 实现足够聪明,能够检测到这种情况并在插入之前执行删除,但这是它们经常失败的地方。或者,如果您的数据库支持延迟约束检查(例如,Oracle 支持但 MySQL 不支持) ),数据库将通过等待提交时间给出唯一约束违规异常来处理此问题。

因此,一种解决方案是在调用remove(entity1)之后执行额外的提交。另一种可能性是,在创建实体2之前,首先检查它是否存在于数据库中,如果存在,则使用该实体2。这两个选项都可能有点麻烦,并且并不适合所有工作流程。您可能想要深入研究当前 JPA 实现的文档,看看它们是否提供任何可能有帮助的扩展。

I don't think there is any standard way to specify operational ordering in JPA, so there is no guarantee which order the statements will be executed. Ideally, the JPA implementation would be clever enough to detect this situation and perform the delete before the insert, but that is an area they frequently fail in. Alternatively, if your database supported deferred constraint checking (e.g., Oracle does but MySQL doesn't), the database would handle this by waiting until commit time to give the unique constraint violation exception.

So one solution is to just perform an extra commit after your call to remove(entity1). Another possibility would be, before you create entity2, to first check to see if it exists in the database, and if so, just use that one. Both these options can be somewhat cumbersome and not be suitable for all workflows. You might want to dig into the documentation for your current JPA implementation to see if they offer any extensions that might help.

梦罢 2024-08-21 21:47:53

我遇到了同样的问题,涉及 UC 和以错误顺序发生的插入/删除。我必须为我的实体创建一个与 UC 的列相匹配的复合键。之后,删除和插入按正确的顺序发生。请参阅这篇文章,以及有关添加 @EmbeddedId 的评论:

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

I had the same problem involving a UC and the insertions/deletions occurring in the wrong order. I had to create a composite key for my entity that matched the columns of the UC. After that, the deletions and insertions occurred in the correct order. See this post, and the comment about adding an @EmbeddedId:

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

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文