带有 JPA/EJB 代码的“将分离的实体传递给持久性错误”

IT小君   2021-09-26T06:20:09

我正在尝试运行这个基本的 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 分配修复了它。

但我没有明白,我需要修改什么才能使代码正常工作?

点击广告,支持我们为你提供更好的服务
评论(9)
IT小君

发生错误是因为设置了对象的 ID。Hibernate 区分瞬态对象和分离对象,并且persist仅适用于瞬态对象。如果persist得出结论该对象已分离(因为设置了 ID),它将返回“已分离对象传递给持久化”错误。您可以在此处此处找到更多详细信息

然而,这仅适用于如果您指定的主键是自动生成的:如果该字段设置为始终手动设置,那么你的代码的作品。

2021-09-26T06:20:09   回复
IT小君

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

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

2021-09-26T06:20:09   回复
IT小君

消除

user.setId(1);

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

2021-09-26T06:20:10   回复
IT小君

我得到了答案,我正在使用:

em.persist(user);

我用合并代替坚持:

em.merge(user);

但不知道,为什么坚持不起作用。:(

2021-09-26T06:20:10   回复
IT小君

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

替换user.setId (1)user.setId (null),问题解决。

2021-09-26T06:20:10   回复
IT小君

这里.persist()只会插入记录。如果我们使用.merge()它将检查是否存在任何具有当前 ID 的记录,如果存在,它将更新,否则将插入新记录。

2021-09-26T06:20:10   回复
IT小君

我知道为时已晚,每个人都得到了答案。但是要添加一点:当设置 GenerateType 时,对象上的 persist() 预计会生成一个 id。

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

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

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

2021-09-26T06:20:11   回复
IT小君

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

user.setId(1);

试试这个:

public static void main(String[] args){
         UserBean user = new UserBean();
         user.setUserName("name1");
         user.setPassword("passwd1");
         em.persist(user);
  }
2021-09-26T06:20:11   回复
IT小君

我有这个问题,它是由二级缓存引起的:

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

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

2021-09-26T06:20:11   回复