使用 JPA/EJB 代码“传递分离实体以持久化错误”

我尝试运行这个基本的 JPA/EJB 代码:

public static void main(String[] args){
UserBean user = new UserBean();
user.setId(1);
user.setUserName("name1");
user.setPassword("passwd1");
em.persist(user);
}

我得到了这个错误:

javax.ejb.EJBException: javax.persistence.PersistenceException: org.hibernate.PersistentObjectException: detached entity passed to persist: com.JPA.Database

有什么想法吗?

我在互联网上搜索,发现的原因是:

这是由于你如何创建的对象,即。如果显式设置 ID 属性。移除 ID 分配修复了它。

但是我没有得到它,我需要修改什么才能让代码工作呢?

157019 次浏览

我得到了答案,我用的是:

em.persist(user);

我使用 merge 代替 keep:

em.merge(user);

但不知道,为什么坚持不下去了

发生错误是因为设置了对象的 ID。Hibernate 区分瞬态对象和分离对象,而 persist仅适用于瞬态对象。如果 persist断定对象被分离(这是因为设置了 ID) ,它将返回“已分离的对象被传递给持久化”错误。你可以找到更多的细节 给你给你

但是,这只适用于指定要自动生成的主键的 如果: 如果将字段配置为始终手动设置,则代码可以正常工作。

ERD

假设您有两个实体 AlbumPhoto。相册包含许多照片,因此它是一对多关系。

专辑课

@Entity
public class Album {
@Id
@GeneratedValue(strategy=GenerationType.AUTO)
Integer albumId;


String albumName;


@OneToMany(targetEntity=Photo.class,mappedBy="album",cascade={CascadeType.ALL},orphanRemoval=true)
Set<Photo> photos = new HashSet<Photo>();
}

摄影课

@Entity
public class Photo{
@Id
@GeneratedValue(strategy=GenerationType.AUTO)
Integer photo_id;


String photoName;


@ManyToOne(targetEntity=Album.class)
@JoinColumn(name="album_id")
Album album;


}

在持久化或合并之前,您必须做的是在每张照片中设置相册引用。

        Album myAlbum = new Album();
Photo photo1 = new Photo();
Photo photo2 = new Photo();


photo1.setAlbum(myAlbum);
photo2.setAlbum(myAlbum);

这就是在持久化或合并之前如何附加相关实体的方法。

我遇到了这个问题,它是由第二级缓存引起的:

  1. 我使用休眠持久化了一个实体
  2. 然后,我删除了从一个单独的进程创建的行,该进程没有与第二级缓存交互
  3. 我用相同的标识符保持另一个实体(我的标识符值不是自动生成的)

因此,由于缓存没有失效,hibernate 假设它正在处理同一实体的一个分离实例。

拿开

user.setId(1);

因为它是在数据库上自动生成的, 并继续执行“持久化”命令。

我知道这有点太晚了,但愿每个人都得到了答案。但是还有一点需要补充: 当 GenerateType 被设置时,对象上的 keep ()预计将获得一个 id 生成。

如果用户已经为 Id 设置了一个值,那么 hibernate 将其视为已保存的记录,因此将其视为已分离的记录。

如果 id 为 null-在这种情况下,当类型为 AUTO 或 IDENTITY 等时会引发 null 指针异常,除非 id 是从表或序列等生成的。

Design: 当表有一个 bean 属性作为主键时,就会发生这种情况。 只有在自动生成 id 时才必须设置 GenerateType。 删除此选项,插入操作应该与用户指定的 id 一起工作。 (将属性映射到主键字段是一种糟糕的设计)

这里 。坚持()只会插入记录。如果我们使用 。合并(),它将检查是否有任何记录存在与当前的 ID,如果它存在,它将更新,否则它将插入一个新的记录。

如果您使用在您的实体中生成 id = GenerationType.AUTO策略。

user.setId (null)代替 user.setId (1),解决了这个问题。

如果您将数据库中的 id 设置为主键和自增量,那么这行代码是错误的:

user.setId(1);

试试这个:

public static void main(String[] args){
UserBean user = new UserBean();
user.setUserName("name1");
user.setPassword("passwd1");
em.persist(user);
}