JPA EntityExistsException

时间:2013-05-09 11:34:10

标签: jpa

我目前面临的问题如下:

Exception in thread "main" javax.persistence.EntityExistsException: a different object with the same identifier value was already associated with the session: [de.entities.Genre#28]
at org.hibernate.ejb.AbstractEntityManagerImpl.convert(AbstractEntityManagerImpl.java:1359)
at org.hibernate.ejb.AbstractEntityManagerImpl.convert(AbstractEntityManagerImpl.java:1310)
at org.hibernate.ejb.AbstractEntityManagerImpl.convert(AbstractEntityManagerImpl.java:1316)
at org.hibernate.ejb.AbstractEntityManagerImpl.persist(AbstractEntityManagerImpl.java:881)
at de.model.DatabaseBuilder.importData(DatabaseBuilder.java:87)
at de.main.Main.main(Main.java:55)

因此Exception告诉我,我想插入两个具有相同主键ID的不同对象。

我想要使用JPA插入数据库的所有数据都来自XML文件。我用SAXParser解析这个文件。当然,有很多类型为28的流派条目,因为很多电影都有相同的类型。

如果我使用自动生成的ID,则数据将不再正确,因为XML文件正确地给出了所有id。

我该如何解决这个问题?为什么JPA不只是忽略了这个事实,这个对象已经存在于数据库中,只是在我的m:n表中插入电影和类型的id?

4 个答案:

答案 0 :(得分:2)

要么直接调用你的Genre实例上的持久性,要么你正在调用电影,而电影 - >类型映射已经级联持续存在。 JPA要求提供程序在分离的实体上调用persist时抛出异常,因为persist意味着您希望提供程序插入它,并且它已经分离,因为它已经存在。所以你会得到一个例外。听起来你的解析器无法判断Genre实体是同一个实例,因此创建了相同数据的多个实例。如果无法解决此问题,您可以尝试使用合并。合并将首先检查实体实例是新实例还是分离实例。如果它是新的,它将插入,而如果它是分离的,它将检索数据并在数据库中更新它。

其他选项是确保您不在分离的Genre实例上调用persist。删除关系上的级联持久设置,并确保您手动调用持久化或合并新的Genre实例,而不是依赖级联持久设置。

答案 1 :(得分:1)

您无法插入具有相同标识符的两个元素。 id 必须唯一,如果没有,数据库无法识别对象(讽刺的是),这就是为什么它会给你例外。

创建一个名为movieId的新字段(或任何您想要命名的字段),并将xml中的id存储在该字段中,但不存储在数据库标识符“id”中

答案 2 :(得分:1)

您不能插入具有相同标识符(id)的两个对象。 它抛出EntityExistsException,

  

如果实体已经存在。         (如果实体已经存在,则在调用persist操作时可能会抛出EntityExistsException,或者可能在刷新或提交时抛出EntityExistsException或另一个PersistenceException。)

解决方案

您可以为movieId创建一个新字段,该字段将存储XML中电影的ID。但这会造成不必要的数据冗余。对于流派,您应该创建一个新表,在其中定义movie_genre映射。为此,您可以使用一对多映射。

答案 3 :(得分:0)

你的流派映射似乎有错误的关系。从您的用例来看,我认为它应该是一个多对多的关系。

您的流派的有效映射应如下所示:

@ManyToMany(fetch = FetchType.EAGER, cascade = { CascadeType.MERGE, CascadeType.REFRESH, })
@JoinTable(name = "MovieGenre", joinColumns = { @JoinColumn(name = "Movie_Id") }, inverseJoinColumns = { @JoinColumn(name = "Genre_Id") })
public Set<Genre> getGenres() {
     return this.genres;
}